package xcmg.device.service.threeGuaranteesPur;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.barcode.BarcodeManageDO;
import xcmg.device.dao.entity.company.CompanyDealerDO;
import xcmg.device.dao.entity.company.CompanyInfoDO;
import xcmg.device.dao.entity.delivery.DeliveryReceiptMaterialDO;
import xcmg.device.dao.entity.threeGuaranteesPur.ThreeGuaranteesOutBarcodeDO;
import xcmg.device.dao.entity.threeGuaranteesPur.ThreeGuaranteesOutDO;
import xcmg.device.dao.entity.threeGuaranteesPur.ThreeGuaranteesOutDetailDO;
import xcmg.device.dao.entity.threeGuaranteesPur.ThreeGuaranteesPurDO;
import xcmg.device.dao.entity.threeGuaranteesPur.ThreeGuaranteesPurDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseDO;
import xcmg.device.dao.entity.warehouse.WarehouseDeliveryDO;
import xcmg.device.dao.entity.warehouse.WarehouseDeliveryDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseDeliveryRecordDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDO;
import xcmg.device.dao.entity.warehouse.WarehouseInventoryDO;
import xcmg.device.dao.mapper.BarcodeManageMapper;
import xcmg.device.dao.mapper.CompanyDealerMapper;
import xcmg.device.dao.mapper.CompanyInfoMapper;
import xcmg.device.dao.mapper.MaterialLocationRelationMapper;
import xcmg.device.dao.mapper.delivery.DeliveryReceiptLinkMapper;
import xcmg.device.dao.mapper.delivery.DeliveryReceiptMaterialMapper;
import xcmg.device.dao.mapper.threeGuaranteesPur.ThreeGuaranteesOutBarcodeMapper;
import xcmg.device.dao.mapper.threeGuaranteesPur.ThreeGuaranteesOutDetailMapper;
import xcmg.device.dao.mapper.threeGuaranteesPur.ThreeGuaranteesOutMapper;
import xcmg.device.dao.mapper.threeGuaranteesPur.ThreeGuaranteesPurDetailMapper;
import xcmg.device.dao.mapper.threeGuaranteesPur.ThreeGuaranteesPurMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseAreaLocationDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryRecordMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInventoryMapper;
import xcmg.device.infra.DateUtil;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExportUtil;
import xcmg.device.infra.enums.BarcodeStatus;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.infra.enums.WornoutReturnStatusEnum;
import xcmg.device.service.ExternalParamCheckService;
import xcmg.device.service.GenDocumentService;
import xcmg.device.service.abnormal.AbnormalOutService;
import xcmg.device.service.barcode.BarcodeService;
import xcmg.device.service.company.CompanyDealerService;
import xcmg.device.service.delivery.DeliveryNoteService;
import xcmg.device.service.delivery.DeliveryReceiptMaterialService;
import xcmg.device.service.vo.ExternalParamCheckVO;
import xcmg.device.service.vo.barcode.BarcodeManageVO;
import xcmg.device.service.vo.barcode.SplitNumVO;
import xcmg.device.service.vo.basic.MaterialLocationRelationVO;
import xcmg.device.service.vo.delivery.DeliveryReceiptMaterialVO;
import xcmg.device.service.vo.permission.WareHousePermission;
import xcmg.device.service.vo.threeGuaranteesOut.SapOrderSeearchParam;
import xcmg.device.service.vo.threeGuaranteesOut.ThreeGuaranteesOutDetailBarcodeSaveParam;
import xcmg.device.service.vo.threeGuaranteesOut.ThreeGuaranteesOutDetaildSaveBarcode;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesOutAddVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesOutDetailBarcodeResultVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesOutDetailBarcodeVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesOutDetailVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesOutVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesPurAddVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesPurDetailVO;
import xcmg.device.service.vo.warehouse.FindMaterialsInfos;
import xcmg.device.service.vo.warehouse.FindMaterialsNumParam;
import xcmg.device.service.vo.warehouse.WarehouseDeliveryDetailVO;
import xcmg.device.service.vo.warehouse.WarehouseDeliveryRecordAddVO;
import xcmg.device.service.vo.warehouse.app.EnableAndOccupyVO;
import xcmg.device.service.vo.warehouse.sap.ObligateVO;
import xcmg.device.service.warehouse.CommonService;
import xcmg.device.service.warehouse.DepartmentWarehouseRelationService;
import xcmg.device.service.warehouse.WarehouseDeliveryDetailService;
import xcmg.device.service.warehouse.WarehouseDeliveryService;
import xcmg.device.service.warehouse.WarehouseInventoryService;
import xcmg.device.service.warehouse.WarehouseInventorySplitService;
import xcmg.device.service.warehouse.allot.RegionAllotDetailService;
import xcmg.device.service.warehouse.allot.RegionAllotService;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.infra.log.LogHelper;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.PageHelperPlus;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
@Slf4j
public class ThreeGuaranteesOutService {
    @Autowired
    private FastGenClient fastGenClient;

    @Autowired
    private GenDocumentService genDocumentService;

    @Autowired
    private ThreeGuaranteesOutMapper threeGuaranteesOutMapper;

    @Autowired
    private ThreeGuaranteesOutDetailMapper threeGuaranteesOutDetailMapper;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private CommonService commonService;

    @Autowired
    private WarehouseDeliveryService warehouseDeliveryService;

    @Autowired
    private ThreeGuaranteesPurService threeGuaranteesPurService;

    @Autowired
    private MaterialLocationRelationMapper materialLocationRelationMapper;

    @Autowired
    private WarehouseDeliveryDetailMapper warehouseDeliveryDetailMapper;

    @Autowired
    private WarehouseInventoryService warehouseInventoryService;

    @Autowired
    private CompanyDealerMapper companyDealerMapper;

    @Autowired
    private WarehouseDeliveryMapper warehouseDeliveryMapper;

    @Autowired
    private ThreeGuaranteesPurMapper threeGuaranteesPurMapper;

    @Autowired
    private DeliveryReceiptLinkMapper deliveryReceiptLinkMapper;

    @Autowired
    private DeliveryReceiptMaterialService deliveryReceiptMaterialService;

    @Autowired
    private DeliveryReceiptMaterialMapper deliveryReceiptMaterialMapper;

    @Autowired
    private CompanyDealerService companyDealerService;
    @Autowired
    private WarehouseInventoryMapper warehouseInventoryMapper;
    @Autowired
    private WarehouseAreaLocationDOMapper warehouseAreaLocationDOMapper;

    @Autowired
    private ThreeGuaranteesPurDetailMapper threeGuaranteesPurDetailMapper;
    @Autowired
    private ThreeGuaranteesOutBarcodeMapper threeGuaranteesOutBarcodeMapper;
    @Autowired
    private BarcodeManageMapper barcodeManageMapper;
    @Autowired
    private WarehouseDOMapper warehouseDOMapper;
    @Autowired
    private CompanyInfoMapper companyInfoMapper;
    @Autowired
    private BarcodeService barcodeService;
    @Autowired
    private WarehouseDeliveryDetailService warehouseDeliveryDetailService;

    @Autowired
    private ThreeGuaranteesOutService threeGuaranteesOutService;
    @Autowired
    private AbnormalOutService abnormalOutService;
    @Autowired
    private RegionAllotDetailService regionAllotDetailService;

    @Autowired
    private DeliveryNoteService deliveryNoteService;

    @Autowired
    private ExternalParamCheckService externalParamCheckService;
    @Autowired
    private RegionAllotService regionAllotService;
    @Autowired
    private DepartmentWarehouseRelationService relationService;

    @Autowired
    private WarehouseInventorySplitService warehouseInventorySplitService;
    @Autowired
    private WarehouseInboundMapper warehouseInboundMapper;
    @Autowired
    private WarehouseDeliveryRecordMapper warehouseDeliveryRecordMapper;
//    @Value("${sc.threeout.default.location}")
//    private String scThreeOutDefaultLocation;
//    @Value("${sc.threeout.default.area}")
//    private String scThreeOutDefaultArea;
//    @Value("${sc.threeout.default.createId}")
//    private String scThreeOutDefaultCreateId;
//    @Value("${sc.threeout.default.createName}")
//    private String scThreeOutDefaultCreateName;
//    @Value("${sc.threeout.default.createPartId}")
//    private String scThreeOutDefaultCreatePartId;
//    @Value("${sc.threeout.default.createPartName}")
//    private String scThreeOutDefaultCreatePartName;

    /**
     * 出库状态：手动完成
     */
    private static final Integer OUT_STATUS_FINISH = 3;

    /**
     * 过账状态。2已过账
     */
    private static final Integer POST_STATUS_YES = 2;


    @Transactional(rollbackFor = Exception.class)
    public ErrorCode add(ThreeGuaranteesOutAddVO threeGuaranteesOutAddVO, String orgId, String userId)throws Exception{
        ThreeGuaranteesOutDO threeGuaranteesOutDO = new ThreeGuaranteesOutDO();
        BeanUtils.copyProperties(threeGuaranteesOutAddVO.getHeaderInfo(),threeGuaranteesOutDO);
        ActionResult<String> text = fastGenClient.textGuid();
        if (text.getCode() != ErrorCode.Success.getCode()) {
            return ErrorCode.IllegalArument;
        }
        threeGuaranteesOutDO.setId(text.getValue());
        threeGuaranteesOutDO.setGuaranteesOutNo(genDocumentService.getDocumentNo(BillDesc.ThreeOut));
        threeGuaranteesOutDO.setOrgId(orgId);
        threeGuaranteesOutDO.setCreateId(userId);
        threeGuaranteesOutDO.setCreateName(commonService.getUserName(userId));
        threeGuaranteesOutDO.setCreateDate(new Date());
        threeGuaranteesOutDO.setOutLocationStatus(0);
        List<FindMaterialsInfos> infos=new ArrayList<>();
        for (ThreeGuaranteesOutDetailVO detailVO : threeGuaranteesOutAddVO.getDetailList()) {
             FindMaterialsInfos findMaterialsInfos=new FindMaterialsInfos();
             findMaterialsInfos.setMaterialsNo(detailVO.getMaterialsNo());
             findMaterialsInfos.setAmount(detailVO.getDeliveryQty());
             infos.add(findMaterialsInfos);
        }
        FindMaterialsNumParam findMaterialsNumParam=new FindMaterialsNumParam();
        findMaterialsNumParam.setMaterialsNos(infos);
        findMaterialsNumParam.setOrgId(orgId);
        findMaterialsNumParam.setWarehousCode(threeGuaranteesOutAddVO.getHeaderInfo().getOutLocation());
        if(!warehouseInventoryService.findMaterialsNum(findMaterialsNumParam)){
            return ErrorCode.PartMaterialsNotNumber;
        }
        boolean success;
        for(ThreeGuaranteesOutDetailVO detailVO:threeGuaranteesOutAddVO.getDetailList()){
            if(detailVO.getDeliveryQty() == null ){
                continue;
            }

            if (qtyIsOver(threeGuaranteesOutDO.getPurchaseNo(), detailVO)) {
                return ErrorCode.ThreeOutQtyError;
            }

            ThreeGuaranteesOutDetailDO threeGuaranteesOutDetailDO = new ThreeGuaranteesOutDetailDO();
            BeanUtils.copyProperties(detailVO,threeGuaranteesOutDetailDO);
            ActionResult<String> textDetail=fastGenClient.textGuid();
            if(textDetail.getCode()!=ErrorCode.Success.getCode()){
                return ErrorCode.IllegalArument;
            }
            threeGuaranteesOutDetailDO.setId(textDetail.getValue().toString());
            threeGuaranteesOutDetailDO.setGuaranteesOutNo(threeGuaranteesOutDO.getId());
            threeGuaranteesOutDetailDO.setRealOutQty(BigDecimal.ZERO);
            BigDecimal deliveryQty = detailVO.getDeliveryQty() == null ? BigDecimal.ZERO : detailVO.getDeliveryQty();
            BigDecimal outQty = detailVO.getOutQty() == null ? BigDecimal.ZERO : detailVO.getOutQty();
            threeGuaranteesOutDetailDO.setOutQty(deliveryQty.add(outQty));
            threeGuaranteesOutDetailDO.setOutLocationStatus(0);
            threeGuaranteesOutDetailDO.setPackNumber(BigDecimal.ZERO);
            success = threeGuaranteesOutDetailMapper.add(threeGuaranteesOutDetailDO)> 0;
            if(!success){
                throw new Exception("生成三包出库详情记录失败");
            }

            //更新其他三包出库单的已发货数量
            threeGuaranteesOutDetailMapper.updateOutQty(orgId, threeGuaranteesOutDetailDO.getOutQty(),
                    threeGuaranteesOutDO.getPurchaseNo(), detailVO.getMaterialsNo());

            //更新三包申请详情发货数量
            success = threeGuaranteesPurService.updateDetailQty(threeGuaranteesOutDO.getPurchaseNo(), threeGuaranteesOutDetailDO.getMaterialsNo(),
                    threeGuaranteesOutDetailDO.getOutQty(), orgId);
            if(!success){
                throw new Exception("更新三包申请详情发货数量失败");
            }
        }

        ThreeGuaranteesPurDO threeGuaranteesPurDO=threeGuaranteesPurService.itemByNo(threeGuaranteesOutDO.getPurchaseNo(),threeGuaranteesOutDO.getOrgId());
        if(threeGuaranteesPurDO==null)
        {
            throw new Exception("三包申请单异常");
        }
        if (StringUtils.isBlank(threeGuaranteesPurDO.getCustomerId())) {
           // throw new Exception("三包申请单异常,客户信息不存在");
        }else{
            CompanyDealerDO companyDealerDO = companyDealerMapper.item(Long.parseLong(threeGuaranteesPurDO.getCustomerId()));
            if (companyDealerDO != null) {
                threeGuaranteesOutDO.setPurchaseOrgId(companyDealerDO.getDealerOrgId());
                threeGuaranteesOutDO.setPurchaseOrgName(companyDealerDO.getCompanyName());
            }
        }
        threeGuaranteesOutDO.setSettleTypeId(threeGuaranteesPurDO.getSettleTypeId());
        threeGuaranteesOutDO.setSettleTypeName(threeGuaranteesPurDO.getSettleTypeName());
        threeGuaranteesOutDO.setDeliveryTypeId(threeGuaranteesPurDO.getDeliveryTypeId());
        threeGuaranteesOutDO.setDeliveryTypeName(threeGuaranteesPurDO.getDeliveryTypeName());
        threeGuaranteesOutDO.setReceiverName(threeGuaranteesPurDO.getReceiverName());
        threeGuaranteesOutDO.setReceiverPhone(threeGuaranteesPurDO.getReceiverPhone());
        threeGuaranteesOutDO.setReceiverFax(threeGuaranteesPurDO.getReceiverFax());
        threeGuaranteesOutDO.setAddress(threeGuaranteesPurDO.getReceiverAddress());
        threeGuaranteesOutDO.setSendTypeChildId(threeGuaranteesPurDO.getSendTypeChildId());
        threeGuaranteesOutDO.setSendTypeChildName(threeGuaranteesPurDO.getSendTypeChildName());
        threeGuaranteesOutDO.setServiceNo(threeGuaranteesPurDO.getServiceNo());
        success = threeGuaranteesOutMapper.add(threeGuaranteesOutDO)>0;
        if(!success){
            throw new Exception("生成三包出库主记录失败");
        }

        //生成出库事物单
        threeGuaranteesOutAddVO.getHeaderInfo().setGuaranteesOutNo(threeGuaranteesOutDO.getGuaranteesOutNo());
        success = warehouseDeliveryService.saveByThreeGuaranteesOut(threeGuaranteesOutAddVO, userId, orgId);
        if(!success){
            throw new Exception("生成出库事物单失败");
        }

        //更新三包申请单可出库状态
        success = threeGuaranteesPurService.resetPurchaseStatus(threeGuaranteesOutDO.getPurchaseNo(),orgId);
        if(!success){
            throw new Exception("更新三包申请单可出库状态失败");
        }

        return ErrorCode.Success;
    }


    /**
     * 保存出库的条码信息，把塔机传过来的零件详情中每条数据的条码，数量进行保存
     * @param detailVO
     * @throws Exception
     */
    private void saveOutBarcode(String threeGuaranteesNo,String threeGuaranteesOutDetailId, ThreeGuaranteesOutDetailVO detailVO,ThreeGuaranteesPurAddVO model) throws Exception {
        if(detailVO == null){
            return ;
        }
        String materialsNo = detailVO.getMaterialsNo();
        List<ThreeGuaranteesPurDetailVO> originDetailList = model.getOriginDetailList();
        for(ThreeGuaranteesPurDetailVO originDetail : originDetailList){
            String originalMaterialNo = originDetail.getMaterialsNo();
            if(materialsNo.equals(originalMaterialNo)){
                String barcode = originDetail.getBarcode();
                if(StringUtils.isEmpty(barcode)){
                    return;
                }
                ThreeGuaranteesOutBarcodeDO saveData = new ThreeGuaranteesOutBarcodeDO();
                ActionResult<String> barcodeIdResult = fastGenClient.textGuid();
                if (barcodeIdResult.getCode() != ErrorCode.Success.getCode()) {
                    throw new Exception("获取GUID出错");
                }
                saveData.setId(barcodeIdResult.getValue());
                saveData.setThreeGuaranteesOutDetailId(threeGuaranteesOutDetailId);
                saveData.setBarcode(barcode);
                saveData.setNum(originDetail.getPurchaseQty());
                saveData.setGuaranteesOutNo(threeGuaranteesNo);
                saveData.setMaterialsNo(originalMaterialNo);
                threeGuaranteesOutBarcodeMapper.addBarcodeRecord(saveData);
            }
        }
    }

    public List<ThreeGuaranteesOutBarcodeDO> guaranteesOutDetailBarcodes(String outDetailId){
        if(StringUtils.isEmpty(outDetailId)){
            return Collections.EMPTY_LIST;
        }
        List<ThreeGuaranteesOutBarcodeDO> barcodes = threeGuaranteesOutBarcodeMapper.getByOutDetailId(outDetailId);
        if(CollectionUtils.isEmpty(barcodes)){
            return Collections.EMPTY_LIST;
        }
        return barcodes;
    }

    /**新增条码信息
     * */
    public void addThreeGuaranteesOutBarcodeDOs(List<ThreeGuaranteesOutBarcodeDO> doList) throws Exception {
        if(CollectionUtils.isEmpty(doList)){
            return;
        }
        for(ThreeGuaranteesOutBarcodeDO barcode : doList){
            ActionResult<String> barcodeIdResult = fastGenClient.textGuid();
            if (barcodeIdResult.getCode() != ErrorCode.Success.getCode()) {
                throw new Exception("获取GUID出错");
            }
            barcode.setId(barcodeIdResult.getValue());
        }
        threeGuaranteesOutBarcodeMapper.batchInsert(doList);
    }

    /**
     * 更新记录
     * @param doList
     */
    public void udpateThreeGuranteesOutBarcodes(List<ThreeGuaranteesOutBarcodeDO> doList){
        if(CollectionUtils.isEmpty(doList)){
            return;
        }
        threeGuaranteesOutBarcodeMapper.batchUpdate(doList);
    }

    /**
     * 判断零件已发货数量是否超出
     *
     * @param purchaseNo
     * @param detailVO
     * @return
     */
    private boolean qtyIsOver(String purchaseNo, ThreeGuaranteesOutDetailVO detailVO) {
        BigDecimal hasDeliveryQty = threeGuaranteesOutDetailMapper.countHasDeliveryQty(purchaseNo,detailVO.getMaterialsNo());
        if (null == hasDeliveryQty || hasDeliveryQty.compareTo(BigDecimal.ZERO) == 0) {
            return false;
        }
        return hasDeliveryQty.add(detailVO.getDeliveryQty()).compareTo(detailVO.getQty()) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode remove(List<String> ids, String orgId)throws Exception{
        if(ListUtil.isNullOrEmpty(ids)){
            return ErrorCode.IllegalArument;
        }
        if(!ListUtil.isNullOrEmpty(threeGuaranteesOutMapper.findForDeleteByIds(ids))){
            return ErrorCode.ThreeOutDeleteError;
        }

        List<String> orderList = threeGuaranteesOutMapper.findOrderList(ids);
        List<ThreeGuaranteesOutDO> purchaseNoList = threeGuaranteesOutMapper.findPurchaseNoList(ids);
        if(ListUtil.isNullOrEmpty(orderList) || ListUtil.isNullOrEmpty(purchaseNoList)){
            return ErrorCode.IllegalArument;
        }
        Map<String, String> map = new HashMap<>();
        for(ThreeGuaranteesOutDO outDO : purchaseNoList){
            map.put(outDO.getId(), outDO.getPurchaseNo());
        }
        List<ThreeGuaranteesOutDetailDO> detailDOList;
        boolean success;
        List<DeliveryReceiptMaterialVO> receiptMaterialList = new ArrayList<>();
        Set<String> receIds = new HashSet<>();
        //更新三包申请单、其他三包出库单出库数量
        for(String id : ids){
            detailDOList = threeGuaranteesOutDetailMapper.list(id);
            List<String> receiptIds = deliveryReceiptLinkMapper.findReceiptIds(id);
            receIds.addAll(receiptIds);
            if(ListUtil.isNullOrEmpty(detailDOList)){
                throw new Exception("删除失败");
            }
            for(ThreeGuaranteesOutDetailDO detailDO : detailDOList){
                success = threeGuaranteesPurService.updateDetailQty(map.get(id), detailDO.getMaterialsNo(),
                        detailDO.getOutQty().subtract(detailDO.getDeliveryQty()), orgId);
                if(!success){
                    if(ListUtil.isNullOrEmpty(detailDOList)){
                        throw new Exception("更新三包申请单出库数量失败");
                    }
                }
                //更新其他三包出库单的已发货数量
                threeGuaranteesOutDetailMapper.updateOutQty(orgId, detailDO.getOutQty().subtract(detailDO.getDeliveryQty()),
                        map.get(id), detailDO.getMaterialsNo());

                if(!ListUtil.isNullOrEmpty(receiptIds)){
                    for(String receiptId : receiptIds){
                        DeliveryReceiptMaterialVO receiptMaterialDO = new DeliveryReceiptMaterialVO();
                        receiptMaterialDO.setDeliveryReceiptId(receiptId);
                        receiptMaterialDO.setMaterialsNo(detailDO.getMaterialsNo());
                        receiptMaterialDO.setQty(detailDO.getDeliveryQty());
                        receiptMaterialDO.setUpdateType(0);
                        receiptMaterialList.add(receiptMaterialDO);
                    }
                }
            }
            //更新三包申请单可出库状态
            success = threeGuaranteesPurService.resetPurchaseStatus(map.get(id),orgId);
            if(!success){
                throw new Exception("更新三包申请单可出库状态失败");
            }

            if(!ListUtil.isNullOrEmpty(receiptIds)){
                for(String receiptId : receiptIds){
                    deliveryReceiptLinkMapper.deleteItem(receiptId, id);
                }
            }
        }
        success = threeGuaranteesOutMapper.remove(ids)>0;
        if(!success){
            throw new Exception("删除主表记录失败");
        }
        success = threeGuaranteesOutDetailMapper.removeByOutIds(ids)>0;
        if(!success){
            throw new Exception("删除详情记录失败");
        }
        //删除出库事物单
        success = warehouseDeliveryService.removeByBusinessOrders(orderList, orgId).getCode()==0;
        if(!success){
            throw new Exception("删除出库事物单失败");
        }
        //更新发运交接单
        deliveryReceiptMaterialService.updateByAdjust(new ArrayList<>(receIds),receiptMaterialList);
        return ErrorCode.Success;
    }

    @Transactional(rollbackFor = Exception.class)
    public synchronized ErrorCode update(ThreeGuaranteesOutAddVO threeGuaranteesOutAddVO, String orgId)throws Exception{
        ThreeGuaranteesOutDO threeGuaranteesOutDO = new ThreeGuaranteesOutDO();
        BeanUtils.copyProperties(threeGuaranteesOutAddVO.getHeaderInfo(),threeGuaranteesOutDO);

        //先判断发货数量是否大于剩余数量
        List<FindMaterialsInfos> infos=new ArrayList<>();
        for(ThreeGuaranteesOutDetailVO detailVO:threeGuaranteesOutAddVO.getDetailList()){
            if(detailVO.getDeliveryQty().compareTo(detailVO.getRealOutQty()) < 0){
                return ErrorCode.ThreeOutDeliveryQtyError;
            }
            BigDecimal temp = detailVO.getOutQty().subtract(detailVO.getLastDeliveryQty()).add(detailVO.getDeliveryQty());
            if(temp.compareTo(detailVO.getQty())>0){
                return ErrorCode.ThreeOutQtyError;
            }
            if(detailVO.getOutLocationStatus()<=1){
                FindMaterialsInfos findMaterialsInfos=new FindMaterialsInfos();
                findMaterialsInfos.setMaterialsNo(detailVO.getMaterialsNo());
                findMaterialsInfos.setAmount(detailVO.getDeliveryQty().subtract(detailVO.getRealOutQty()));
                infos.add(findMaterialsInfos);
            }
        }
        FindMaterialsNumParam findMaterialsNumParam=new FindMaterialsNumParam();
        findMaterialsNumParam.setMaterialsNos(infos);
        findMaterialsNumParam.setOrgId(orgId);
        findMaterialsNumParam.setBusinessOrder(threeGuaranteesOutAddVO.getHeaderInfo().getGuaranteesOutNo());
        findMaterialsNumParam.setWarehousCode(threeGuaranteesOutAddVO.getHeaderInfo().getOutLocation());
        if(!warehouseInventoryService.findMaterialsNum(findMaterialsNumParam)){
            return ErrorCode.PartMaterialsNotNumber;
        }
        boolean success;
        boolean allComplete = true;
        boolean someComplete = false;
        boolean manulComplete = false;
        List<String> receiptIds = deliveryReceiptLinkMapper.findReceiptIds(threeGuaranteesOutDO.getId());
        List<DeliveryReceiptMaterialVO> receiptMaterialVOList = new ArrayList<>();
        for(ThreeGuaranteesOutDetailVO detailVO:threeGuaranteesOutAddVO.getDetailList()){

            ThreeGuaranteesOutDetailDO inDetailDO =   threeGuaranteesOutDetailMapper.findByNo(detailVO.getGuaranteesOutNo(),detailVO.getMaterialsNo());

            if(inDetailDO.getOutLocationStatus() != null && (inDetailDO.getOutLocationStatus()==2||inDetailDO.getOutLocationStatus()==3))
            {
                if(inDetailDO.getOutLocationStatus()==3){
                    manulComplete = true;
                }
                someComplete = true;
                continue;//零件状态已完成，不可以编辑
            }

            ThreeGuaranteesOutDetailDO detailDO = new ThreeGuaranteesOutDetailDO();
            BeanUtils.copyProperties(detailVO,detailDO);
            detailDO.setOutQty(detailVO.getOutQty().subtract(detailVO.getLastDeliveryQty()).add(detailVO.getDeliveryQty()));

            if(detailDO.getDeliveryQty().compareTo(detailDO.getRealOutQty()) > 0){
                if(allComplete){
                    allComplete = false;
                }
                if(detailDO.getRealOutQty().compareTo(BigDecimal.ZERO) == 0){
                    detailDO.setOutLocationStatus(0);
                }else{
                    detailDO.setOutLocationStatus(1);
                    someComplete = true;
                }
            }else{
                someComplete = true;
                detailDO.setOutLocationStatus(2);
            }

            success = threeGuaranteesOutDetailMapper.update(detailDO)>0;
            if(!success){
                throw new Exception("更新三包出库详情记录失败");
            }

            //更新出库事物单详情记录
            ErrorCode errorCode = warehouseDeliveryService.updateDetailState(threeGuaranteesOutDO.getGuaranteesOutNo(), detailDO.getMaterialsNo(),
                    detailDO.getDeliveryQty(), detailDO.getOutLocationStatus(), orgId);
            if(errorCode.getCode() != 0){
                throw new Exception("更新出库事物单详情记录失败");
            }

            //更新其他三包出库单的已发货数量
            threeGuaranteesOutDetailMapper.updateOutQty(orgId, detailDO.getOutQty(), threeGuaranteesOutDO.getPurchaseNo(), detailVO.getMaterialsNo());

            //更新三包申请详情发货数量
            success = threeGuaranteesPurService.updateDetailQty(threeGuaranteesOutDO.getPurchaseNo(), detailVO.getMaterialsNo(), detailDO.getOutQty(), orgId);
            if(!success){
                throw new Exception("更新三包出库详情发货数量失败");
            }

            for(String receiptId : receiptIds){
                DeliveryReceiptMaterialVO receiptMaterialVO = new DeliveryReceiptMaterialVO();
                receiptMaterialVO.setMaterialsNo(detailDO.getMaterialsNo());
                receiptMaterialVO.setOldQty(inDetailDO.getDeliveryQty());
                receiptMaterialVO.setQty(detailDO.getDeliveryQty());
                receiptMaterialVO.setDeliveryReceiptId(receiptId);
                receiptMaterialVO.setUpdateType(1);
                receiptMaterialVOList.add(receiptMaterialVO);
            }
        }
        if(allComplete){
            if(manulComplete){
                threeGuaranteesOutDO.setOutLocationStatus(3);
            }else{
                threeGuaranteesOutDO.setOutLocationStatus(2);
            }
        }else if(someComplete){
            threeGuaranteesOutDO.setOutLocationStatus(1);
        }else{
            threeGuaranteesOutDO.setOutLocationStatus(0);
        }
        success = threeGuaranteesOutMapper.update(threeGuaranteesOutDO)>0;
        if(!success){
            throw new Exception("更新三包出库单记录失败");
        }

        //更新出库事务单
        ErrorCode errorCode = warehouseDeliveryService.updateState(threeGuaranteesOutDO.getGuaranteesOutNo(), threeGuaranteesOutDO.getOutLocationStatus(), orgId);
        if(errorCode.getCode() != 0){
            throw new Exception("更新出库事务单记录失败");
        }

        //更新三包申请单可出库状态
        success = threeGuaranteesPurService.resetPurchaseStatus(threeGuaranteesOutDO.getPurchaseNo(),orgId);
        if(!success){
            throw new Exception("更新三包申请单可出库状态失败");
        }

        //更新发运交接单
        deliveryReceiptMaterialService.updateByAdjust(receiptIds, receiptMaterialVOList);
        return ErrorCode.Success;
    }


//    public static void main(String[] args) throws Exception {
//        JSONObject object = new JSONObject();
//
//        object.put("new_srv_partsapply_id", "test_ordno");
//        object.put("new_code", "12345678");
//        object.put("new_shippedqty", 10);
//        object.put("statuscode", 100000001);
//        object.put("new_senddate", DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
//        object.put("new_price", 100);
//        System.out.println(object.toString());
//
//        String result = HttpRequestUtil.jsonPost("http://10.17.0.57:8087/api/GPS/Partsapplydetail", object.toString());
//        System.out.println(result);
//    }

    public PageCommonVO list(SearchCommonVO<ThreeGuaranteesOutVO> condition,String orgId,String deptId){
        ThreeGuaranteesOutVO searchVO = condition.getFilters();
        //如果guaranteesOutList值大于1，则循环此list，否则查询条件只有一个单号，直接模糊查询此单号
        List<String> guaOutNos = xcmg.device.infra.StringUtil.getStrSplitList(searchVO.getGuaranteesOutNo());
        if (CollectionUtils.isNotEmpty(guaOutNos) && guaOutNos.size() > 1) {
            searchVO.setGuaranteesOutList(guaOutNos);
        }

        if(searchVO.getOutLocation()!=null){
            searchVO.setOutLocation(searchVO.getOutLocation().toUpperCase());
        }
        condition.getFilters().setBillNosList(xcmg.device.infra.StringUtil.splitList(condition.getFilters().getBillNos()));
        String purchaseNames = condition.getFilters().getPurchaseNames();
        if(!StringUtils.isEmpty(purchaseNames)){
            List<String> purchaseNamesList = companyDealerService.listFullNamesByShortName(orgId,purchaseNames);
            if (CollectionUtils.isEmpty(purchaseNamesList)) {
                PageCommonVO result = new PageCommonVO();
                result.setPageInfo(new PageInfo(Collections.EMPTY_LIST));
                result.setPageInfoList(Collections.EMPTY_LIST);
                return result;
            }else{
                condition.getFilters().setPurchaseNamesList(purchaseNamesList);
            }
        }

        PageCommonVO result = new PageCommonVO();
        //查询是否有企业空间-->组织架构-->仓库配置的限制
        WareHousePermission wareHousePermission = relationService.hasMajorWareHousePermission(orgId, deptId);
        if (!wareHousePermission.isHasPermission()) {
            result.setPageInfo(new PageInfo(new ArrayList()));
            result.setPageInfoList(new ArrayList<>());
            return result;
        } else {
            condition.getFilters().setWarehousePermitList(wareHousePermission.getPermissionWarehouses());
        }
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<ThreeGuaranteesOutDO> doList = threeGuaranteesOutMapper.list(searchVO);
        List<ThreeGuaranteesOutVO> voList = new ArrayList<>();
        for (ThreeGuaranteesOutDO entity : doList) {
            ThreeGuaranteesOutVO model = new ThreeGuaranteesOutVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        result.setPageInfo(new PageInfo(doList));
        result.setPageInfoList(voList);
        return result;
    }

    public ThreeGuaranteesOutAddVO item(String guaranteesOutNo){
        ThreeGuaranteesOutAddVO result = new ThreeGuaranteesOutAddVO();
        ThreeGuaranteesOutDO threeGuaranteesOutDO = threeGuaranteesOutMapper.item(guaranteesOutNo);
        if(threeGuaranteesOutDO == null){
            return result;
        }
        ThreeGuaranteesOutVO threeGuaranteesOutVO = new ThreeGuaranteesOutVO();
        BeanUtils.copyProperties(threeGuaranteesOutDO,threeGuaranteesOutVO);
        ThreeGuaranteesPurDO purDO = threeGuaranteesPurMapper.itemByNo(threeGuaranteesOutDO.getPurchaseNo(), threeGuaranteesOutDO.getOrgId());
        if(purDO == null){
            return result;
        }
        threeGuaranteesOutVO.setAgentId(purDO.getCustomerId());
        threeGuaranteesOutVO.setAgentName(purDO.getCustomerName());
        threeGuaranteesOutVO.setSettleTypeName(purDO.getSettleTypeName());
        threeGuaranteesOutVO.setDeliveryTypeName(purDO.getDeliveryTypeName());
        threeGuaranteesOutVO.setReceiverName(purDO.getReceiverName());
        threeGuaranteesOutVO.setReceiverAddress(purDO.getReceiverAddress());
        threeGuaranteesOutVO.setReceiverPhone(purDO.getReceiverPhone());
        result.setHeaderInfo(threeGuaranteesOutVO);
        List<ThreeGuaranteesOutDetailVO> listVO = new ArrayList<>();
        List<ThreeGuaranteesOutDetailDO> listDO = threeGuaranteesOutDetailMapper.listForLocationUser(guaranteesOutNo);
        MaterialLocationRelationVO relationVO = new MaterialLocationRelationVO();
        EnableAndOccupyVO enableAndOccupyVO;
        for(ThreeGuaranteesOutDetailDO entity:listDO) {
            //查储位信息
            ThreeGuaranteesOutDetailVO model = new ThreeGuaranteesOutDetailVO();
            BeanUtils.copyProperties(entity, model);
            relationVO.setOrgId(threeGuaranteesOutVO.getOrgId());
            relationVO.setMaterialNo(entity.getMaterialsNo());
            relationVO.setWarehouseCode(threeGuaranteesOutVO.getOutLocation());
            relationVO.setAreaCode(threeGuaranteesOutVO.getOutArea());
            //model.setLocationCode(materialLocationRelationMapper.findLocationCode(relationVO));
            List<String> locationCodeList = warehouseInventoryMapper.findLocationCode(relationVO.getOrgId(), relationVO.getMaterialNo(), relationVO.getWarehouseCode(), relationVO.getAreaCode());
            if (locationCodeList != null && locationCodeList.size() > 0) {
                model.setLocationCode(String.join(",", locationCodeList));
            }

            if (locationCodeList != null && locationCodeList.size() > 0) {
                List<String> locationDescList = new ArrayList<>();
                for (String locationCode : locationCodeList) {
                    String locationDesc = warehouseAreaLocationDOMapper.getLocationDesc(locationCode);
                    locationDescList.add(locationDesc);
                }
                model.setLocationDesc(String.join(",", locationDescList));
            }
            enableAndOccupyVO = warehouseInventoryService.findEnableAndOccupyNum(entity.getMaterialsNo(), threeGuaranteesOutVO.getOrgId(), threeGuaranteesOutDO.getOutLocation());
            BeanUtils.copyProperties(enableAndOccupyVO, model);
            listVO.add(model);
        }

        sortDetailsByLocation(listVO);
        result.setDetailList(listVO);
        return result;
    }

    /**
     * @Des 获取三包出库单信息（打印单据时使用）
     * @Date 2020/12/29 17:26
     * @Author wangzhaoyu
     * @Param [guaranteesOutNo]
     * @Return xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesOutAddVO
     */
    public ThreeGuaranteesOutAddVO itemPrintInfo(String guaranteesOutNo){
        ThreeGuaranteesOutAddVO result = new ThreeGuaranteesOutAddVO();
        ThreeGuaranteesOutDO threeGuaranteesOutDO = threeGuaranteesOutMapper.item(guaranteesOutNo);
        if(threeGuaranteesOutDO == null){
            return result;
        }
        ThreeGuaranteesOutVO threeGuaranteesOutVO = new ThreeGuaranteesOutVO();
        BeanUtils.copyProperties(threeGuaranteesOutDO,threeGuaranteesOutVO);
        ThreeGuaranteesPurDO purDO = threeGuaranteesPurMapper.itemByNo(threeGuaranteesOutDO.getPurchaseNo(), threeGuaranteesOutDO.getOrgId());
        if(purDO == null){
            return result;
        }
        threeGuaranteesOutVO.setAgentId(purDO.getCustomerId());
        threeGuaranteesOutVO.setAgentName(purDO.getCustomerName());
        threeGuaranteesOutVO.setSettleTypeName(purDO.getSettleTypeName());
        threeGuaranteesOutVO.setDeliveryTypeName(purDO.getDeliveryTypeName());
        threeGuaranteesOutVO.setReceiverName(purDO.getReceiverName());
        threeGuaranteesOutVO.setReceiverAddress(purDO.getReceiverAddress());
        threeGuaranteesOutVO.setReceiverPhone(purDO.getReceiverPhone());
        result.setHeaderInfo(threeGuaranteesOutVO);
        List<ThreeGuaranteesOutDetailVO> listVO = new ArrayList<>();
        List<ThreeGuaranteesOutDetailDO> listDO = threeGuaranteesOutDetailMapper.listForLocationUser(guaranteesOutNo);
        MaterialLocationRelationVO relationVO = new MaterialLocationRelationVO();
        for(ThreeGuaranteesOutDetailDO entity:listDO) {
            //查储位信息
            ThreeGuaranteesOutDetailVO model = new ThreeGuaranteesOutDetailVO();
            BeanUtils.copyProperties(entity, model);
            Integer outLocationStatus = entity.getOutLocationStatus();
            if(outLocationStatus != null && outLocationStatus.compareTo(3) == 0){
                BigDecimal realOutQty = entity.getRealOutQty() == null ? BigDecimal.ZERO : entity.getRealOutQty();

            }
            relationVO.setOrgId(threeGuaranteesOutVO.getOrgId());
            relationVO.setMaterialNo(entity.getMaterialsNo());
            relationVO.setWarehouseCode(threeGuaranteesOutVO.getOutLocation());
            relationVO.setAreaCode(threeGuaranteesOutVO.getOutArea());
            List<String> locationCodeList = warehouseInventoryMapper.findLocationCode(relationVO.getOrgId(), relationVO.getMaterialNo(), relationVO.getWarehouseCode(), relationVO.getAreaCode());
            if (locationCodeList != null && locationCodeList.size() > 0) {
                model.setLocationCode(String.join(",", locationCodeList));
            }

            if (locationCodeList != null && locationCodeList.size() > 0) {
                List<String> locationDescList = new ArrayList<>();
                for (String locationCode : locationCodeList) {
                    String locationDesc = warehouseAreaLocationDOMapper.getLocationDesc(locationCode);
                    locationDescList.add(locationDesc);
                }
                model.setLocationDesc(String.join(",", locationDescList));
            }
            listVO.add(model);
        }

        sortDetailsByLocation(listVO);
        result.setDetailList(listVO);
        return result;
    }

    private void sortDetailsByLocation(List<ThreeGuaranteesOutDetailVO> listVO){
        Collections.sort(listVO, new Comparator<ThreeGuaranteesOutDetailVO>() {
            @Override
            public int compare(ThreeGuaranteesOutDetailVO o1, ThreeGuaranteesOutDetailVO o2) {
                if (o1.getLocationCode()==null && o2.getLocationCode()==null){
                    return 0;
                }else if (o1.getLocationCode()==null){
                    return -1;
                }else if (o2.getLocationCode()==null){
                    return 1;
                }else {
                    return o1.getLocationCode().compareTo(o2.getLocationCode());
                }
            }
        });
    }


    private List<ThreeGuaranteesOutAddVO> exportAllItem(ThreeGuaranteesOutVO condition){
        List<ThreeGuaranteesOutAddVO> result = new ArrayList<>();
        List<ThreeGuaranteesOutDO> threeGuaranteesOutDOList = threeGuaranteesOutMapper.exportItem(condition);
        if(threeGuaranteesOutDOList == null || threeGuaranteesOutDOList.isEmpty()){
            return result;
        }

        for (ThreeGuaranteesOutDO threeGuaranteesOutDO: threeGuaranteesOutDOList) {
            ThreeGuaranteesOutAddVO tempResult = new ThreeGuaranteesOutAddVO();
            ThreeGuaranteesOutVO threeGuaranteesOutVO = new ThreeGuaranteesOutVO();
            BeanUtils.copyProperties(threeGuaranteesOutDO,threeGuaranteesOutVO);
            threeGuaranteesOutVO.setReceiverAddress(threeGuaranteesOutDO.getAddress());
            tempResult.setHeaderInfo(threeGuaranteesOutVO);

            List<ThreeGuaranteesOutDetailVO> listVO = new ArrayList<>();
            List<ThreeGuaranteesOutDetailDO> listDO = threeGuaranteesOutDO.getListDO();
            for(ThreeGuaranteesOutDetailDO entity:listDO){
                //查储位信息
                ThreeGuaranteesOutDetailVO model = new ThreeGuaranteesOutDetailVO();
                BeanUtils.copyProperties(entity,model);
//                model.setLocationCode(entity.getStockLocation());
                model.setEnableNum(warehouseInventoryMapper.findEnableNum(entity.getMaterialsNo(), threeGuaranteesOutDO.getOrgId(), threeGuaranteesOutDO.getOutLocation()));
                listVO.add(model);
            }
            tempResult.setDetailList(listVO);
            result.add(tempResult);
        }
        return result;
    }

    //导出
    public void export(List<String> threeGuaranteesIds) throws Exception{
        List<ThreeGuaranteesOutAddVO>  addVOList=new ArrayList<>();
      //  List<ThreeGuaranteesOutDO> voList =threeGuaranteesOutMapper.findByIds(threeGuaranteesIds);
        for(String  ids:threeGuaranteesIds){
            addVOList.add(item(ids));
        }
        invokeExport(addVOList);
    }

    public void exportAll(ThreeGuaranteesOutVO condition) throws Exception{
        condition.setBillNosList(xcmg.device.infra.StringUtil.splitList(condition.getBillNos()));
        condition.setPurchaseNamesList(xcmg.device.infra.StringUtil.splitList(condition.getPurchaseNames()));
        PageHelperPlus.startPage(0, 60000);
        List<ThreeGuaranteesOutAddVO> dataList = exportAllItem(condition);
        invokeExport(dataList);
    }

    private void invokeExport( List<ThreeGuaranteesOutAddVO> voList)throws Exception{
        String title = "三包出库导出";
        String[] rowsName = new String[]{"序号","三包出库单号","单据类型","调出库位",
                "制单人","制单时间","出库状态","零件编码","零件名称","默认储位","可用库存",
                "单位","订单总数","已发数量","出库数量","实际出库数量","出库状态","库存储位",
                "保管员","预留单号","三包申请单号","服务信息单号","过账时间","服务人员",
                "服务网点","车型","车号","零件凭证","地址","备注","CRM单据号","出库时间"};
        List<Object[]>  dataList = new ArrayList<>();
        Object[] objs;
        if(CollectionUtils.isEmpty(voList)){
            ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
            exportUtil.export(response);
            return;
        }
        for (int i = 0; i < voList.size(); i++) {
            Boolean flag = false;
            int size = 1;
            ThreeGuaranteesOutAddVO threeGuaranteesOutAddVO = voList.get(i);
            ThreeGuaranteesOutVO e = threeGuaranteesOutAddVO.getHeaderInfo();
            if(!CollectionUtils.isEmpty(threeGuaranteesOutAddVO.getDetailList())){
                flag = true;
                size = threeGuaranteesOutAddVO.getDetailList().size();
            }
            for(int o = 0 ; o<size ; o++){
                objs = new Object[rowsName.length];
                objs[0] = o+1;
                objs[1] =e.getGuaranteesOutNo();
                objs[2] = e.getGuaranteesTypeName();
                objs[3] = e.getOutLocation();
                objs[4]=e.getCreateName();
                objs[5]= DateUtil.formatDateTime(e.getCreateDate());
                objs[6]=getStatusDesc(e.getOutLocationStatus());
                if(flag){
                   ThreeGuaranteesOutDetailVO t=threeGuaranteesOutAddVO.getDetailList().get(o);
                    objs[7]=t.getMaterialsNo();
                    objs[8]=t.getMaterialsDesc()==null?"":t.getMaterialsDesc();
                    objs[9]=t.getStockLocation()==null?"":t.getStockLocation();
                    objs[10]=t.getEnableNum()==null?"0":t.getEnableNum();
                    objs[11]=t.getUnit()==null?"":t.getUnit();
                    objs[12]=t.getQty()==null?"":t.getQty();
                    objs[13]=t.getOutQty()==null?"":t.getOutQty();
                    objs[14]=t.getDeliveryQty()==null?"":t.getDeliveryQty();
                    objs[15]=t.getRealOutQty()==null?"":t.getRealOutQty();
                    objs[16]=getStatusDesc(t.getOutLocationStatus());
                    objs[17]=t.getLocationCode();
                    objs[18]=t.getStockUserName();
                }
                objs[19]=e.getSapOrder()==null?"":e.getSapOrder();
                objs[20]=e.getPurchaseNo()==null?"":e.getPurchaseNo();
                objs[21] = e.getServiceNo();
                objs[22] = e.getPostDate() == null ? "" : DateUtil.formatDateTime(e.getPostDate());
                objs[23] = e.getServiceName();
                objs[24] = e.getServiceSite();
                objs[25] = e.getProdType();
                objs[26] = e.getMachineNumber();
                objs[27] = e.getVoucherNo();
                objs[28] = e.getReceiverAddress();
                objs[29] = e.getNote();
                objs[30] = e.getCrmOrder();
                objs[31] = e.getUpdateStateDate() == null ? "" : DateUtil.formatDateTime(e.getUpdateStateDate());
                dataList.add(objs);
            }
        }
        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    private String getStatusDesc(Integer statusId){
        if(statusId==null){
            return "";
        }
        switch(statusId){
            case 0:
            default:
                return "未出库";
            case 1:
                return "部分出库";
            case 2:
                return "已出库";
            case 3:
                return "强制结单";
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateByOutbound(String threeOrder, String materialNo, BigDecimal realAmount,
                                    Integer singelState, Integer totalState, String orgId, boolean updateReceipt)throws Exception{
        ThreeGuaranteesOutVO outVO = new ThreeGuaranteesOutVO();
        outVO.setOrgId(orgId);
        outVO.setGuaranteesOutNo(threeOrder);
        List<ThreeGuaranteesOutDO> outDOList = threeGuaranteesOutMapper.list(outVO);
        if(ListUtil.isNullOrEmpty(outDOList)){
            throw new Exception("未找到三包出库单记录");
        }
        ThreeGuaranteesOutDO outDO = outDOList.get(0);

        ThreeGuaranteesOutDetailDO detailDO = threeGuaranteesOutDetailMapper.findByNo(outDO.getId(), materialNo);
        if(detailDO == null){
            throw new Exception("未找到三包出库单详情记录");
        }
        BigDecimal nowAmount = realAmount;
        if(detailDO.getRealOutQty() != null){
            nowAmount = realAmount.subtract(detailDO.getRealOutQty());
        }
        detailDO.setRealOutQty(realAmount);
        detailDO.setOutLocationStatus(singelState);
        boolean success = threeGuaranteesOutDetailMapper.update(detailDO)>0;
        if(success){
            //更新三包出库单记录
            outDO.setOutLocationStatus(totalState);
            outDO.setUpdateStateDate(new Date());
            success = threeGuaranteesOutMapper.update(outDO)>0;
            if(!success){
                return false;
            }

            //更新三包申请单状态
            success = threeGuaranteesPurService.updateByOutBound(outDO.getPurchaseNo(), materialNo, nowAmount, orgId);
            if(!success){
                return false;
            }

            if(updateReceipt){
                //更新发运交接单状态
                List<String> ids = deliveryReceiptLinkMapper.findReceiptIds(outDO.getId());
                if(!ListUtil.isNullOrEmpty(ids)){
                    List<DeliveryReceiptMaterialDO>  receiptMaterialDOList = deliveryReceiptMaterialMapper.listByIds(ids, materialNo);
                    if(!ListUtil.isNullOrEmpty(receiptMaterialDOList)){
                        for(DeliveryReceiptMaterialDO receiptMaterialDO : receiptMaterialDOList){
                            deliveryReceiptMaterialService.updateByOut(receiptMaterialDO, receiptMaterialDO.getOutQty().add(nowAmount));
                        }
                    }
                }
            }

            if(totalState == 2){//同步到sap创建预留单
                List<ObligateVO> obligateVOList = new ArrayList<>();
                ObligateVO obligateVO;
                List<ThreeGuaranteesOutDetailDO> outDetailDOS = threeGuaranteesOutDetailMapper.list(outDO.getId());
                for (ThreeGuaranteesOutDetailDO outDetailDO: outDetailDOS) {
                    //同步到SAP创建预留单
                    obligateVO = new ObligateVO();
                    obligateVO.setMaterialNo(outDetailDO.getMaterialsNo());
                    obligateVO.setAmount(outDetailDO.getDeliveryQty());
                    obligateVO.setMoveType(outDO.getSapTypeName());
                    obligateVO.setWarehouseCode(outDO.getOutLocation());
                    obligateVO.setSapOutArea(outDO.getSapOutArea());
                    obligateVO.setInnerOrder(outDO.getSapId());
                    obligateVOList.add(obligateVO);
                }

                //同步到SAP创建预留单，异步方式调用接口
//                ObligateHeaderVO headerVO = new ObligateHeaderVO();
//                headerVO.setBusinesId(outDO.getId());
//                headerVO.setBusinesOrder(outDO.getGuaranteesOutNo());
//                headerVO.setBusinesSingle(outDO.getGuaranteesOutNo().substring(0, 4));
//                sapCommonService.createObligateOrder(headerVO, obligateVOList, null , orgId);
            }
        }
        return success;
    }

    /**
     * 手动完成单据<br>
     *     materialsNo 不为null,则更改该单据下的零件状态为“手动完成”状态；如果materialsNo为空，则更改整个单据为“手动完成”状态
     * @param billNo  String 单据编号
     * @param materialsNo String 零件编号
     * @param orgId String 企业ID
     * @return ErrorCode 返回码
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode manualFinish(String billNo,String materialsNo,String orgId)throws Exception
    {
        ThreeGuaranteesOutDO outDO =  threeGuaranteesOutMapper.itemByNo(billNo,orgId);
        if(outDO == null){
            return ErrorCode.IllegalArument;
        }
        boolean success = threeGuaranteesPurService.updateByManulFinish(outDO, materialsNo, orgId);
        if(!success){
            throw new Exception("更新三包申请状态失败");
        }
        if (StringUtil.isNullOrEmpty(materialsNo))//零件编码为空，更新单据状态为“手动完成”
        {
            outDO.setOutLocationStatus(OUT_STATUS_FINISH);
            outDO.setPostStatus(POST_STATUS_YES);
            threeGuaranteesOutMapper.update(outDO);

            warehouseDeliveryService.updateState(billNo,3,orgId);

            threeGuaranteesOutDetailMapper.updateStatus(3,outDO.getId(),null);
            warehouseDeliveryDetailMapper.updateAllStatus(3, billNo, orgId);
        }
        else
        {
            threeGuaranteesOutDetailMapper.updateStatus(3,outDO.getId(),materialsNo);
            warehouseDeliveryService.updateDetailState(billNo,materialsNo,null,3,orgId);
            ErrorCode errorCode = checkBillFinished(billNo,outDO.getId(),orgId);

            if(ErrorCode.Success!=errorCode)
            {
                return errorCode;
            }
        }
        return ErrorCode.Success;
    }

    /**
     * 校验单据是否已完成<br>
     *     判断单据下的所有零件是否已经完成，如果都完成，则更改单据状态为完成
     * @param billNo String
     * @param orgId String
     * @return Boolean
     */
    private ErrorCode checkBillFinished(String billNo,String billId,String orgId)throws Exception
    {
        List<ThreeGuaranteesOutDetailDO> outDetailDOs = threeGuaranteesOutDetailMapper.list(billId);
        if(ListUtil.isNullOrEmpty(outDetailDOs)){
            throw new Exception("未查询到三包出库单详情列表");
        }
        boolean manul = false;
        boolean flag = true;
        boolean doube=false;
        boolean stocks=false;
        int status;
        for (ThreeGuaranteesOutDetailDO temp : outDetailDOs)
        {
            if(null==temp.getOutLocationStatus())
            {
                flag =false;
                continue;
            }
            if(temp.getOutLocationStatus()==1){
                doube=true;
            }
            if(temp.getOutLocationStatus()==2){
                stocks=true;
            }
            if(temp.getOutLocationStatus() == 3){
                manul = true;
            }
            if (2==temp.getOutLocationStatus() || 3==temp.getOutLocationStatus())
            {
                //完成状态
                continue;
            }

            flag =false;
        }
         if(flag){
            if(manul){
                status = 3;
            }else{
                status = 2;
            }
        }else if (doube||stocks){
            status=1;
        }else{
             status = 0;
         }

        threeGuaranteesOutMapper.updateStatus(status,billNo);
        warehouseDeliveryService.updateState(billNo,status,orgId);
        return ErrorCode.Success;
    }

    /**
     * @Author: WangKe
     * @Description: 更新三包出库单和出库事务单的冲销状态
     * @Date: 2018/7/11 0011
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean updateReverseState(ThreeGuaranteesOutDO threeGuaranteesOutDO, Integer state, String orgId)throws Exception{
        ThreeGuaranteesOutDO noteDO = new ThreeGuaranteesOutDO();
        noteDO.setId(threeGuaranteesOutDO.getId());
        noteDO.setIsReverse(state);
        boolean success = threeGuaranteesOutMapper.update(noteDO)>0;
        if(!success){
            throw new Exception("更新三包出库单状态失败");
        }
        WarehouseDeliveryDO deliveryDO = warehouseDeliveryMapper.findByBusinessOrder(threeGuaranteesOutDO.getGuaranteesOutNo(), orgId);
        if(deliveryDO == null){
            throw new Exception("未找到相关联的出库事务单");
        }
        deliveryDO.setReverseState(state);
        success = warehouseDeliveryMapper.updateByPrimaryKey(deliveryDO)>0;
        if(!success){
            throw new Exception("更新出库事务单状态失败");
        }
        return true;
    }

    /**
     * 查询sap预留号
     *
     * @param sapOrderSeearchParam 查询参数
     * @return
     */
    public String listSapOrderByThreeApply(SapOrderSeearchParam sapOrderSeearchParam) {

        return String.join(",", threeGuaranteesOutMapper.
            listSapOrderByThreeApply(sapOrderSeearchParam.getThreeGuaPurNo(),
                sapOrderSeearchParam.getMaterialsNo()));
    }

    public ThreeGuaranteesOutDetailBarcodeResultVO outDetailBarcodes(String id){
        ThreeGuaranteesOutDetailBarcodeResultVO result= new ThreeGuaranteesOutDetailBarcodeResultVO();
        ThreeGuaranteesOutDetailBarcodeResultVO.ThreeGuaranteesOutDetailBarcodeResultHead headInfo = result.new ThreeGuaranteesOutDetailBarcodeResultHead();
        List<ThreeGuaranteesOutDetailBarcodeVO> barcodes = new ArrayList<>();
        ThreeGuaranteesOutDetailDO threeGuaranteesOutDetailDO = threeGuaranteesOutDetailMapper.selectById(id);
        if(threeGuaranteesOutDetailDO != null){
            headInfo.setDeliveryQty(threeGuaranteesOutDetailDO.getDeliveryQty());
            headInfo.setDetailId(threeGuaranteesOutDetailDO.getId());
            headInfo.setMaterialsDesc(threeGuaranteesOutDetailDO.getMaterialsDesc());
            headInfo.setMaterialsNo(threeGuaranteesOutDetailDO.getMaterialsNo());
        }
        List<ThreeGuaranteesOutBarcodeDO> threeGuaranteesOutDetailBarcodes = guaranteesOutDetailBarcodes(id);
        if(!CollectionUtils.isEmpty(threeGuaranteesOutDetailBarcodes)){
            for(ThreeGuaranteesOutBarcodeDO barcode : threeGuaranteesOutDetailBarcodes){
                ThreeGuaranteesOutDetailBarcodeVO barcodeVO = new ThreeGuaranteesOutDetailBarcodeVO();
                BeanUtils.copyProperties(barcode,barcodeVO);
                barcodes.add(barcodeVO);
            }
        }
        result.setHeadInfo(headInfo);
        result.setBarcodeList(barcodes);
        return result;
    }

    /**
     * 编辑threeGuarantOutDetailCode的参数进行校验*/
    public ActionResult outDetailBarcodesEditParamCheck(ThreeGuaranteesOutDetailBarcodeSaveParam param){
        String detailId = param.getDetailId();
        ThreeGuaranteesOutDetailDO threeGuaranteesOutDetailDO = threeGuaranteesOutDetailMapper.selectById(detailId);
        if(threeGuaranteesOutDetailDO == null){
            return new ActionResult(ErrorCode.IllegalArument.getCode(),"未查询到记录，无法编辑","未查询到记录，无法编辑");
        }
        List<ThreeGuaranteesOutDetaildSaveBarcode> barcodeList = param.getBarcodeList();
        BigDecimal saveNum = BigDecimal.ZERO ;
        for(ThreeGuaranteesOutDetaildSaveBarcode saveBarcode : barcodeList){
            BigDecimal num = saveBarcode.getNum();
            if(num == null || num.compareTo(BigDecimal.ZERO) <= 0){
                String barcode = saveBarcode.getBarcode();
                return  new ActionResult(ErrorCode.IllegalArument.getCode(),"条码"+barcode+"数量需为正数","条码"+barcode+"数量需为正数");
            }
            saveNum = saveNum.add(num);
        }
        BigDecimal deliveryQty = threeGuaranteesOutDetailDO.getDeliveryQty();
        if(deliveryQty == null || deliveryQty.compareTo(BigDecimal.ZERO) <= 0){
            return new ActionResult(ErrorCode.IllegalArument.getCode(),"该零件编号发货数量不为正数，请联系技术人员","该零件编号发货数量不为正数，请联系技术人员");
        }
        if(deliveryQty.compareTo(saveNum) < 0){
            return new ActionResult(ErrorCode.IllegalArument.getCode(),"条码总量大于发货总量，请检查数据","条码总量大于发货总量，请检查数据");
        }
        return new ActionResult(ErrorCode.Success);
    }

    @Transactional
    public ActionResult editBarcodes(ThreeGuaranteesOutDetailBarcodeSaveParam param) throws Exception {
        String detailId = param.getDetailId();
        List<ThreeGuaranteesOutDetaildSaveBarcode> barcodeList = param.getBarcodeList();
        if(CollectionUtils.isEmpty(barcodeList)){
            return new ActionResult(ErrorCode.Success);
        }
        List<ThreeGuaranteesOutBarcodeDO> needInsert = new ArrayList<>();
        List<ThreeGuaranteesOutBarcodeDO> needUpdate = new ArrayList<>();
        for(ThreeGuaranteesOutDetaildSaveBarcode barcode : barcodeList){
            ThreeGuaranteesOutBarcodeDO barcodeDO = new ThreeGuaranteesOutBarcodeDO();
            barcodeDO.setBarcode(barcode.getBarcode());
            barcodeDO.setThreeGuaranteesOutDetailId(detailId);
            barcodeDO.setNum(barcode.getNum());
            String id = barcode.getId();
            if(StringUtils.isEmpty(id)){
                needInsert.add(barcodeDO);
            }else{
                barcodeDO.setId(id);
                needUpdate.add(barcodeDO);
            }
        }
        //新增和更新之前做一遍数据校验，逻辑是当前outDetail表中已经存在的code要跟需要更新的数据id一一对应(即条数一致)
        List<ThreeGuaranteesOutBarcodeDO> barcodesExised = threeGuaranteesOutService.guaranteesOutDetailBarcodes(detailId);
        if(barcodesExised.size() != needUpdate.size()){
            return new ActionResult(ErrorCode.IllegalArument.getCode(),"请刷新页面重试","请刷新页面重试");
        }
        //进行插入操作
        threeGuaranteesOutService.addThreeGuaranteesOutBarcodeDOs(needInsert);
        //进行更新操作
        threeGuaranteesOutService.udpateThreeGuranteesOutBarcodes(needUpdate);
        return new ActionResult(ErrorCode.Success);
    }

    public List<ThreeGuaranteesOutDetailDO> getMaterialInfoByNo(List<String> guaranteesNoList){
        return threeGuaranteesOutDetailMapper.getMaterialInfoByNo(guaranteesNoList);
    }

    /**
    *@Description 塔机同步服务单使用更换件，返回三包出库单
    *@Author wzy
    *@Date 2020/8/26
    *@Time 9:31
    */
    @Transactional(rollbackFor = Exception.class)
    public ThreeGuaranteesOutDO synServiceTicket4Tj(ThreeGuaranteesPurAddVO model,String outLocation,String orgId) throws Exception {
        //生成三包申请单
        ActionResult<String> actionResult = doAddThreeGuaranteesPur(model);
        //生成三包出库单
        ThreeGuaranteesOutDO threeGuaranteesOutDO = tjThreeGuaranteesOut(model,actionResult.getValue(), outLocation, orgId);
        //自动出库
        String applicationId = model.getHeaderInfo().getApplicationId();
        String applicationName = model.getHeaderInfo().getApplicationName();
        tjDeliveryRecordAddAuto(threeGuaranteesOutDO,orgId,applicationId,applicationName);
        return threeGuaranteesOutDO;
    }

    /**
     * @Des 塔机服务更换件接口自动出库
     * @Date 2020/10/23 11:59
     * @Author wangzhaoyu
     * @Param [threeGuaranteesOutDO]
     * @Return void
     */
    private void tjDeliveryRecordAddAuto(ThreeGuaranteesOutDO threeGuaranteesOutDO,String orgId,String userId,String userName) throws Exception {
        LogHelper.monitor("塔机条码自动出库开始》》》》》》》》》》》》》》》》》》》》");
        log.info("塔机条码自动出库参数为threeGuaranteesOutDO:【{}】",JSON.toJSONString(threeGuaranteesOutDO));
        String guaranteesOutNo = threeGuaranteesOutDO.getGuaranteesOutNo();
        // 获取要自动出库的三包单中的条码详情
        List<ThreeGuaranteesOutBarcodeDO> outBarcodeDOS = threeGuaranteesOutBarcodeMapper.getByGuaranteesOutNo(guaranteesOutNo);
        log.info("塔机条码自动出库条码信息【{}】",outBarcodeDOS);
        // 遍历处理每个条码
        for(ThreeGuaranteesOutBarcodeDO outBarcodeDO : outBarcodeDOS){
            String outBarcode = outBarcodeDO.getBarcode();
            BarcodeManageDO barcodeDO = barcodeManageMapper.item(outBarcode, orgId);
            if(barcodeDO == null){
               log.error("塔机条码自动出库条码【】不存在",outBarcode);
                throw new Exception("条码"+outBarcode+"不存在");
            }
            if(barcodeDO.getBarcodeFlag() == 1 && "3".equals(barcodeDO.getBarcodeStatus())){
                log.info("塔机条码自动出库条码【{}】已拆分",outBarcode);
                throw new Exception("条码"+outBarcode+"已拆分");
            }
            // 根据条码查找库存详情
            List<WarehouseDeliveryRecordAddVO> barcodesInventory = findByBarCodeFromInventory(outBarcodeDO.getNum(),guaranteesOutNo, barcodeDO, orgId);
            log.info("塔机自动出库条码拆分结果为【{}】",JSON.toJSONString(barcodesInventory));
            if(CollectionUtils.isEmpty(barcodesInventory)){
                log.info("条码【{}】出库拆分失败，不出库",outBarcode);
                throw new Exception("条码"+outBarcode+"出库拆分失败");
            }
            // 根据条码拆分信息自动出库
            autoOut(barcodesInventory,guaranteesOutNo,barcodeDO,orgId,userId,userName);
        }
    }

    /**
     * @Des 自动出库
     * @Date 2020/10/23 15:22
     * @Author wangzhaoyu
     * @Param [byBarCodeFromInventory, guaranteesOutNo, barcodeDO, orgId]
     * @Return void
     */
    private void autoOut(List<WarehouseDeliveryRecordAddVO> barcodesInventory,String guaranteesOutNo,BarcodeManageDO barcodeDO,String orgId,String userId,String userName) throws Exception {

        WarehouseDeliveryDetailVO model = new WarehouseDeliveryDetailVO();
        model.setBusinessOrder(guaranteesOutNo);
        model.setMaterialNo(barcodeDO.getMaterialsNo());
        model.setOrgId(orgId);
        List<WarehouseDeliveryDetailDO> deliveryDetailList = warehouseDeliveryDetailMapper.list(model);
        if(ListUtil.isNullOrEmpty(deliveryDetailList)){
            throw new Exception("此零件不属于出库单中零件");
        }

        //判断数量并自动拆分条码
        List<BarcodeManageVO> barcodeManageVOS=  splitBarcode(barcodesInventory, deliveryDetailList.get(0).getAmount(), userId, userName, orgId);
        //批量插入
        for(int i=0; i<barcodesInventory.size(); i++){
            WarehouseDeliveryRecordAddVO recordAddVO = barcodesInventory.get(i);
            addTJThreeOutAutoRecord(recordAddVO, userId, orgId, true);
        }
    }


    /**
     * @Des 创建塔机三包单据自动出库记录
     * @Date 2020/10/26 9:04
     * @Author wangzhaoyu
     * @Param [warehouseDeliveryRecordVO, userId, orgId, isLast]
     * @Return xcmg.device.infra.ErrorCode
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode addTJThreeOutAutoRecord(WarehouseDeliveryRecordAddVO warehouseDeliveryRecordVO, String userId, String orgId, boolean isLast) throws Exception{
        ActionResult<String> textResult = fastGenClient.textGuid();
        if (textResult.getCode() != ErrorCode.Success.getCode()) {
            throw new Exception("自动出库生成主键异常");
        }

        //根据条码获取条码实体
        String barCode = warehouseDeliveryRecordVO.getBarCode();
        BarcodeManageDO barcode = barcodeManageMapper.item(barCode, orgId);
        if(barcode == null){
            throw new Exception("条码"+ barCode +"不存在");
        }
        if(barcode.getBarcodeFlag() == 0){
            throw new Exception(ErrorCode.WarehouseBarcodeNotFound.getDesc());
        }
        //判断条码是否已经扫描出库
        if("2".equals(barcode.getBarcodeStatus())){
            log.error("条码【{}】不能重复出库",barCode);
            throw new Exception(ErrorCode.WarehouseOutboundDuplicate.getDesc());
        }

        //先判断库存表里是否有零件，零件数量是否够
        WarehouseInventoryDO warehouseInventoryDO = warehouseInventoryService.findByBarCode(barCode, orgId);
        if(warehouseInventoryDO == null || warehouseInventoryDO.getIsOut() == 1 ){
            log.error("条码【{}】为查询到库存信息",barCode);
            throw new Exception(ErrorCode.WarehouseNotFound.getDesc());
        }else if(warehouseInventoryDO.getStatus() == 1){
            log.error("条码【{}】零件已冻结",barCode);
            throw new Exception(ErrorCode.WarehouseFrozen.getDesc());
        }else if(warehouseInventoryDO.getAmount().compareTo(warehouseDeliveryRecordVO.getAmount()) < 0){
            log.error("条码【{}】零件数量不足",barCode);
            throw new Exception(ErrorCode.WarehouseAmountNotEqual.getDesc());
        }

        //根据业务单号和零件编码查询出库详情记录
        String businessOrder = warehouseDeliveryRecordVO.getBusinessOrder();
        businessOrder = businessOrder==null?"":businessOrder;
        String buinessSingle = "";

        if(businessOrder.length()>4){
            buinessSingle = businessOrder.substring(0, 4);
        }

        String returnMaterialBusinessSingle = businessOrder.substring(0, 5);

        //查找出库事物主记录，判断是否冲销
        WarehouseDeliveryDO deliveryDO = warehouseDeliveryMapper.findByBusinessOrder(businessOrder, orgId);
        if(deliveryDO == null){
            throw new Exception("未找到相关联的出库事物单主记录");
        }
        if(deliveryDO.getReverseState() != null && (deliveryDO.getReverseState() == 1 || deliveryDO.getReverseState() == 2)){
            throw new Exception("业务单据已被冲销，不允许出库");
        }
        //判断单据是否已经是完成状态
        if( deliveryDO.getStatus() != null && deliveryDO.getStatus() == 4){
            throw new Exception("业务单据已作废！");
        }

        //判断单据是否已经是完成状态
        if(deliveryDO.getStatus() != null && (deliveryDO.getStatus() == 2 || deliveryDO.getStatus() == 3)){
            throw new Exception("业务单据已完成！");
        }
        //判断是否退货
        if(deliveryDO.getIsReturn() != null && deliveryDO.getIsReturn() == 1){
            throw new Exception("业务单据已被退货，不允许出库");
        }

        //判断零件是否属于调出仓库零件
        if(deliveryDO.getWarehouseCode() != null && !deliveryDO.getWarehouseCode().equals(warehouseInventoryDO.getWarehouseCode())){
            throw new Exception("此零件不属于调出仓库零件");
        }

        if (null != deliveryDO.getWarehouseCode()){
            CompanyInfoDO companyInfoDO = companyInfoMapper.item(orgId);
            Integer isBarcode = companyInfoDO.getIsBarcode();
            int countIsBarCode = warehouseDOMapper.countIsBarCode(orgId, deliveryDO.getWarehouseCode());
            if ((null == isBarcode || 0 == isBarcode) && countIsBarCode <= 0){//非条码化企业且仓库不允许条码化返回错误信息
                throw new Exception(ErrorCode.NonBarcodedOutboundNotAllowBarCodeEntry.getDesc());
            }
        }

        //判断零件是否属于调出仓库中库区零件
        if(deliveryDO.getOutArea() != null && !deliveryDO.getOutArea().equals(warehouseInventoryDO.getAreaCode())){
            throw new Exception("此零件不属于调出库区零件");
        }

        //判断零件是否属于出库单中零件
        WarehouseDeliveryDetailVO deliveryDetailVO = new WarehouseDeliveryDetailVO();
        deliveryDetailVO.setBusinessOrder(businessOrder);
        deliveryDetailVO.setMaterialNo(warehouseInventoryDO.getMaterialNo());
        deliveryDetailVO.setOrgId(orgId);
        List<WarehouseDeliveryDetailDO> list = warehouseDeliveryDetailMapper.list(deliveryDetailVO);
        if(ListUtil.isNullOrEmpty(list)){
            throw new Exception("此零件不属于出库单中零件");
        }
        if (list.get(0).getStatus() == 2) {
            throw new Exception("此零件状态已完成");
        }
        if (list.get(0).getStatus() == 3) {
            throw new Exception("此零件状态已结单");
        }
        if(StringUtil.isNullOrEmpty(warehouseDeliveryRecordVO.getDeliveryReceiptNo())){
            if(list.get(0).getAmount().compareTo(warehouseInventoryDO.getAmount()) < 0){
                throw new Exception("实际出库数量不能大于计划出库数量");
            }
        }

        WarehouseDeliveryRecordDO warehouseDeliveryRecordDO = new WarehouseDeliveryRecordDO();
        BeanUtils.copyProperties(warehouseInventoryDO, warehouseDeliveryRecordDO);

        warehouseDeliveryRecordDO.setBarCode(warehouseInventoryDO.getBarCode());
        warehouseDeliveryRecordDO.setBusinessOrder(businessOrder);
        warehouseDeliveryRecordDO.setBusinessSingle(buinessSingle);
        warehouseDeliveryRecordDO.setAmount(warehouseDeliveryRecordVO.getAmount());
        warehouseDeliveryRecordDO.setId(textResult.getValue());
        warehouseDeliveryRecordDO.setCreateDate(new Date());
        warehouseDeliveryRecordDO.setCreaterId(userId);
        warehouseDeliveryRecordDO.setOrgId(orgId);
        warehouseDeliveryRecordDO.setDeliveryOrder(deliveryDO.getDeliveryOrder());
        warehouseDeliveryRecordDO.setCreaterName(commonService.getUserName(userId));
        warehouseDeliveryRecordDO.setDeliveryReceiptNo(warehouseDeliveryRecordVO.getDeliveryReceiptNo());

        boolean isSuccess = warehouseDeliveryRecordMapper.insert(warehouseDeliveryRecordDO)>0;
        if(!isSuccess){
            log.error("出库记录单warehouseDeliveryRecord插入数据失败，插入数据为【{}】",warehouseDeliveryRecordDO);
            throw new Exception("出库记录单操作失败");
        }

        //出库成功，库存表里相关记录更新

        if(isLast){
            //如果是发运交接单出库，有可能是一个条码分多次出库，在最后一次出库时更新条码已出库状态
            ErrorCode barcodeErrorCode = barcodeService.deliveryUpdateBarcode(businessOrder,warehouseDeliveryRecordDO.getBarCode(), BarcodeStatus.Status.OutStorage, orgId, userId,warehouseDeliveryRecordDO.getCreateDate());
            if(barcodeErrorCode.getCode() != 0){
                throw new Exception("生成出库记录时，更新条码状态失败");
            }
            isSuccess = warehouseInventoryService.saveByOutbound(warehouseInventoryDO, warehouseDeliveryRecordDO, userId);
            if(!isSuccess){
                throw new Exception("生成出库记录时，更新库存状态失败");
            }
        }
        Map<String, BigDecimal> map = warehouseDeliveryDetailService.updateByOutbound(warehouseDeliveryRecordDO.getDeliveryOrder(),
                warehouseDeliveryRecordDO.getMaterialNo(), warehouseDeliveryRecordVO.getAmount(), orgId);
        isSuccess = map.get("success").intValue()==1;
        if(!isSuccess){
            throw new Exception("生成出库记录时，更新出库事物单状态失败");
        }

        LogHelper.monitor("buinessSingle------------->"+buinessSingle);
        LogHelper.monitor("returnMaterialBusinessSingle----------------->"+returnMaterialBusinessSingle);

        //更新出库业务单据状态
        BigDecimal realAmount = map.get("realAmount");
        Integer singleState = map.get("singleState").intValue();
        Integer totalState = map.get("totalState").intValue();
        boolean updateReceipt = StringUtil.isNullOrEmpty(warehouseDeliveryRecordVO.getDeliveryReceiptNo());
        //更新三包出库单
        isSuccess = threeGuaranteesOutService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, updateReceipt);
        if(!isSuccess){
            throw new Exception("生成出库记录时，更新三包出库单和详情状态失败");
        }
        return ErrorCode.Success;

    }

    List<BarcodeManageVO> splitBarcode(List<WarehouseDeliveryRecordAddVO> barcodesInventory,BigDecimal amount, String userId,String userName, String orgId) throws Exception {
        log.info("splitBarcode拆分条码的参数为>>>>>barcodesInventory:【{}】;>>>amount>>",barcodesInventory,amount);
        BigDecimal splitAmount = BigDecimal.ZERO;
        List<BarcodeManageVO> results = new ArrayList<>();
        for (WarehouseDeliveryRecordAddVO recordAddVO : barcodesInventory) {
            if (recordAddVO.getSplitAmount().compareTo(BigDecimal.ZERO) == 0) {
                splitAmount = splitAmount.add(recordAddVO.getAmount());
            } else {
                splitAmount = splitAmount.add(recordAddVO.getSplitAmount());
            }
            if (splitAmount.compareTo(amount) > 0) {
                log.info("出库数量为【{}】大于单据数量，不能出库",splitAmount);
                throw new Exception("出库数量不能大于单据数量");
            }
            if (recordAddVO.getSplitAmount().compareTo(BigDecimal.ZERO) > 0) {
                SplitNumVO splitNumVO = new SplitNumVO(recordAddVO.getBarCode(), recordAddVO.getSplitAmount(), recordAddVO.getBusinessOrder());
                BarcodeManageVO barcodeManageVO = splitNum(splitNumVO, userName, userId, orgId);
                recordAddVO.setBarCode(barcodeManageVO.getBarcode());
                recordAddVO.setAmount(barcodeManageVO.getCurrentQty());
                results.add(barcodeManageVO);
            }
        }
        return results;
    }
    
    /**
     * @Des 拆分条码
     * @Date 2020/10/26 8:44
     * @Author wangzhaoyu
     * @Param [splitNumVO, userId, orgId]
     * @Return xcmg.device.service.vo.barcode.BarcodeManageVO
     */
    private BarcodeManageVO splitNum(SplitNumVO splitNumVO,String userId,String userName,String orgId)throws Exception{
        if(splitNumVO.getNum() == null || splitNumVO.getNum().compareTo(BigDecimal.ZERO) == 0){
            throw new Exception("数量不能为0");
        }
        List<WarehouseDeliveryDetailDO> deliveryDetailDOList = warehouseDeliveryDetailMapper.findByBusinessOrder(splitNumVO.getBusinessOrder(), orgId);
        if(ListUtil.isNullOrEmpty(deliveryDetailDOList)){
            throw new Exception("出库单号不正确");
        }
        BarcodeManageDO barcodeManageDO=barcodeManageMapper.item(splitNumVO.getBarcode(), orgId);
        if(barcodeManageDO==null || barcodeManageDO.getIsDel()){
            splitNumVO.setCode(ErrorCode.BarcodeNotFound);
            return null;
        }
        if(!barcodeManageDO.getBarcodeStatus().equals(BarcodeStatus.Status.Printed.toString())&& !barcodeManageDO.getBarcodeStatus().equals(BarcodeStatus.Status.InStorage.toString())){
            splitNumVO.setCode(ErrorCode.BarcodeNotSplit);
            return null;
        }
        if(barcodeManageDO.getCurrentQty().compareTo(splitNumVO.getNum()) <= 0){
            splitNumVO.setCode(ErrorCode.BarcodeNotSplit);
            return null;
        }
        WarehouseDeliveryDetailDO deliveryDetailDO = warehouseDeliveryDetailMapper.itemByMaterialsNo(orgId,splitNumVO.getBusinessOrder(),barcodeManageDO.getMaterialsNo());
        if(deliveryDetailDO == null){
            throw new Exception("此零件不属于此出库单");
        }
        userId = xcmg.device.infra.StringUtil.isEmpty(userId) ? "" : userId ;
        userName = StringUtils.isEmpty(userName) ? "" : userName;
        ActionResult<String> bartextResult = fastGenClient.textGuid();
        if (bartextResult.getCode() != ErrorCode.Success.getCode()) {
            return null;
        }
        Integer seq=barcodeManageMapper.findMaxSeq(barcodeManageDO.getTotalBarcode(),orgId);
        String newBarcode = bartextResult.getValue();
        barcodeManageDO.setTotalQty(barcodeManageDO.getCurrentQty());
        BarcodeManageDO subBarcodeManageDO = new BarcodeManageDO();
        BeanUtils.copyProperties(barcodeManageDO,subBarcodeManageDO);
        subBarcodeManageDO.setBarcode(newBarcode);
        subBarcodeManageDO.setCreateId(userId);
        subBarcodeManageDO.setCreateName(userName);
        subBarcodeManageDO.setCreateTime(new Date());
        subBarcodeManageDO.setCurrentQty(splitNumVO.getNum());
        subBarcodeManageDO.setSeq(seq+1);
        barcodeManageMapper.insert(subBarcodeManageDO);
        BarcodeManageVO subBarcodeVO=new BarcodeManageVO();
        BeanUtils.copyProperties(subBarcodeManageDO,subBarcodeVO);
        if (barcodeManageDO.getBarcodeStatus().equals(BarcodeStatus.Status.InStorage.toString())){
            warehouseInventorySplitService.splitNumber(orgId,barcodeManageDO.getBarcode(),newBarcode,subBarcodeManageDO.getCurrentQty(),userId);
        }
        barcodeManageDO.setCurrentQty(barcodeManageDO.getCurrentQty().subtract(subBarcodeManageDO.getCurrentQty()));
        barcodeManageMapper.update(barcodeManageDO);
        splitNumVO.setCode(ErrorCode.Success);
        subBarcodeVO.setChildCount(seq+1);
        String locationDesc="";
        WarehouseInboundDO inboundDO = warehouseInboundMapper.selectByOrder(subBarcodeVO.getBillNo(), orgId);
        if(inboundDO!=null){
            locationDesc=barcodeManageMapper.locationDesc(subBarcodeVO.getMaterialsNo(),subBarcodeVO.getOrgId(),inboundDO.getWarehouseCode());
        }
        subBarcodeVO.setLocationDesc(locationDesc);
        return subBarcodeVO;
    }

    /**
     * @Des 获取条码拆分信息
     * @Date 2020/10/23 14:12
     * @Author wangzhaoyu
     * @Param [model]
     * @Return yb.ecp.fast.infra.infra.ActionResult
     */
    private List<WarehouseDeliveryRecordAddVO> findByBarCodeFromInventory(BigDecimal outNum,String guaranteesOutNo,BarcodeManageDO barcodeDO,String orgId) throws Exception {
        List<WarehouseDeliveryRecordAddVO> result = new ArrayList<>();
        String barCode = barcodeDO.getBarcode();
        if(outNum == null){
            throw new Exception("出库数量异常");
        }
        WarehouseDeliveryDO deliveryDO = warehouseDeliveryMapper.findByBusinessOrder(guaranteesOutNo, orgId);
        if(deliveryDO == null){
            throw new Exception("未生成出库事务单");
        }

        List<String> barcdoeList = new ArrayList<>();
        if (barcodeDO.getBarcodeFlag() == 0) { //总条码时查询分条码列表
            barcdoeList.addAll(barcodeManageMapper.findBarcodeByTotalBarcode(barCode, orgId));
        } else {
            barcdoeList.add(barCode);
        }
        if (ListUtil.isNullOrEmpty(barcdoeList)) {
            LogHelper.monitor("塔机自动出库条码"+barCode+"无记录");
            throw new Exception("条码"+barCode+"无记录");
        }
        List<WarehouseInventoryDO> inventoryDOList = warehouseInventoryMapper.selectByBarCodeList(barcdoeList, orgId, null);
        if(CollectionUtils.isEmpty(inventoryDOList)){
            LogHelper.monitor("塔机自动出库条码"+barCode+"无库存记录");
            throw new Exception("条码"+barCode+"无库存记录");
        }

        String materialNo = inventoryDOList.get(0).getMaterialNo();
        WarehouseDeliveryDetailDO warehouseDeliveryDetailDO = warehouseDeliveryDetailMapper.itemByMaterialsNo(orgId, deliveryDO.getBusinessOrder(), materialNo);
        if (warehouseDeliveryDetailDO == null) {
            LogHelper.monitor("自动出库零件"+materialNo+"与单据零件不匹配");
            throw new Exception("条码零件"+materialNo+"与单据零件不匹配");
        }
        //出库事务表中还未出库的数量
        BigDecimal noOutAMount = warehouseDeliveryDetailDO.getAmount().subtract(warehouseDeliveryDetailDO.getRealAmount() == null ? BigDecimal.ZERO : warehouseDeliveryDetailDO.getRealAmount());
        if (noOutAMount.compareTo(BigDecimal.ZERO) == 0) {
            throw new Exception("零件已全部出库");
        }
        inventoryDOList = filterInventoryList(deliveryDO, inventoryDOList, orgId);
        if(CollectionUtils.isEmpty(inventoryDOList)){
            throw new Exception("条码"+barCode+"所属仓库与单据出库仓库不一致");
        }

        BigDecimal tempAmount1 = BigDecimal.ZERO;
        BigDecimal tempAmount2 = BigDecimal.ZERO;
        for (WarehouseInventoryDO inventoryDO : inventoryDOList) {
            BigDecimal amount = inventoryDO.getAmount();
            WarehouseDeliveryRecordAddVO recordAddVO = new WarehouseDeliveryRecordAddVO();
            recordAddVO.setAmount(amount);//条码当前数量
            tempAmount1 = tempAmount1.add(amount);
            if (outNum.compareTo(tempAmount1) < 0) {
                recordAddVO.setSplitAmount(outNum.subtract(tempAmount2));//设置拆分数量
            } else {
                recordAddVO.setSplitAmount(BigDecimal.ZERO);//设置拆分数量
            }
            recordAddVO.setBarCode(inventoryDO.getBarCode());//条码
            recordAddVO.setBusinessOrder(guaranteesOutNo);//单据号
            result.add(recordAddVO);
            tempAmount2 = tempAmount2.add(amount);

            if (recordAddVO.getSplitAmount().compareTo(BigDecimal.ZERO) > 0 || outNum.compareTo(tempAmount2) == 0) {
                break;
            }
        }
        //如果走到这里说明全部都不需要拆分，即需要出库的零件数量大于库存数量
        if(outNum.compareTo(tempAmount1) > 0){
            throw new Exception("条码零件数量不足");
        }
        return result;
    }


    private List<WarehouseInventoryDO> filterInventoryList(WarehouseDeliveryDO deliveryDO, List<WarehouseInventoryDO> inventoryDOList, String orgId) throws Exception {
        List<WarehouseInventoryDO> result = new ArrayList<>();
        String warehouseCode = deliveryDO.getWarehouseCode();
        WarehouseDO warehouseDO = warehouseDOMapper.itemByWarehouseCode(orgId, warehouseCode);
        if (warehouseDO == null) {
            LogHelper.monitor("塔机自动出库未找到仓库"+warehouseCode);
            throw new Exception("未找到仓库信息");
        }
        //过滤获取库存表中仓库与本次出库仓库能对上的库存记录
        for (WarehouseInventoryDO inventoryDO : inventoryDOList) {
            if (deliveryDO.getWarehouseCode().equals(inventoryDO.getWarehouseCode())) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(inventoryDO.getCreateDate());
                calendar.add(Calendar.DATE, -1);
                Date now = calendar.getTime();
                if (warehouseDO.getFirstInOut().equals(new Integer("1")) && warehouseInventoryMapper.earliestInventory(orgId, inventoryDO.getMaterialNo(),
                        inventoryDO.getWarehouseCode(), inventoryDO.getAreaCode(), now) > 0) {
                    throw new Exception("该零件存在更早的库存条码");
                }
                result.add(inventoryDO);
            }
        }
        return result;
    }


    private ActionResult doAddThreeGuaranteesPur(ThreeGuaranteesPurAddVO model) throws Exception {
        if (null == model || null == model.getHeaderInfo() || model.getDetailList().isEmpty()) {
            return new ActionResult(ErrorCode.IllegalArument.getCode(),ErrorCode.IllegalArument.getDesc());
        }

        externalParamCheckService.checkParam(fillNeedCheckParan(model));
        ActionResult result = threeGuaranteesPurService.addThreeGuaranteesPur4Tj(model);
        return result;
    }


    private ExternalParamCheckVO fillNeedCheckParan(ThreeGuaranteesPurAddVO model) throws Exception {
        ExternalParamCheckVO param = new  ExternalParamCheckVO();
        if (CollectionUtils.isEmpty(model.getDetailList())) {
            throw new Exception("缺少零件信息");
        }
        List<String> materialsNos = new ArrayList<>();
        for (ThreeGuaranteesPurDetailVO detailVO : model.getDetailList()) {
            materialsNos.add(detailVO.getMaterialsNo());
        }
        param.setMaterialsNos(materialsNos);
        param.setSapCode(model.getHeaderInfo().getSapCode());
        param.setDeliveryTypeId(model.getHeaderInfo().getDeliveryTypeId());
        param.setSettleTypeId(model.getHeaderInfo().getSettleTypeId());
        return param;
    }


    /**
     * 塔机出库单生成
     * @param outLocation
     * @param orgId
     */
    private ThreeGuaranteesOutDO tjThreeGuaranteesOut(ThreeGuaranteesPurAddVO model,String purchaseNo,String outLocation,String orgId) throws Exception {

        ThreeGuaranteesPurDO purDO = threeGuaranteesPurService.itemByPurNo(purchaseNo, orgId);
        ThreeGuaranteesOutVO outVO = new ThreeGuaranteesOutVO();
        List<ThreeGuaranteesOutDetailVO> detailList = new ArrayList<>();
        BeanUtils.copyProperties(purDO, outVO);
        //塔机出库单默认参数赋值
        defaultOutParamAssemble( purDO,outVO,orgId,outLocation);
        //能匹配到出库仓库才进行出库单生成操作
        if(StringUtils.isEmpty(outLocation)){
            throw new Exception("出库仓库未空，无法生成出库");
        }

        ThreeGuaranteesOutDetailVO outDetailVO;
        for (ThreeGuaranteesPurDetailDO purDetailDO : purDO.getPurDetailDOS()) {
            outDetailVO = new ThreeGuaranteesOutDetailVO();
            BeanUtils.copyProperties(purDetailDO, outDetailVO);
            //出库单的已发数量赋值为0和本次发货数量等于接口中的采购数量
            BigDecimal purchaseQty = purDetailDO.getPurchaseQty() == null ? BigDecimal.ZERO : purDetailDO.getPurchaseQty();
            outDetailVO.setDeliveryQty(purchaseQty);
            outDetailVO.setQty(purDetailDO.getPurchaseQty());
            detailList.add(outDetailVO);
        }
        ThreeGuaranteesOutAddVO threeGuaranteesOutAddVO = new ThreeGuaranteesOutAddVO();
        threeGuaranteesOutAddVO.setHeaderInfo(outVO);
        threeGuaranteesOutAddVO.setDetailList(detailList);
        ThreeGuaranteesOutDO threeGuaranteesOutDO = addThreeOut4Tj(model,threeGuaranteesOutAddVO, purDO.getOrgId(), purDO.getDispatcherId());
        // 创建预留单
        try{
            obligate4Tj(threeGuaranteesOutDO,orgId);
        }catch (Exception e){
            LogHelper.monitor("塔机三包出库单创建预留单异常"+e.getMessage());
        }
        return threeGuaranteesOutDO;
    }

    /**
    *@Description 塔机三包出库创建预留单
    *@Author wzy
    *@Date 2020/8/26
    *@Time 10:22
    */
    private void obligate4Tj(ThreeGuaranteesOutDO threeGuaranteesOutDO,String orgId) throws Exception {
        String outId = threeGuaranteesOutDO.getId();
        List<ThreeGuaranteesOutDetailDO> details = threeGuaranteesOutDetailMapper.list(outId);
        List<ObligateVO> obligateVOList = new ArrayList<>();
        ObligateVO obligateVO;
        for (ThreeGuaranteesOutDetailDO outDetailDO: details) {
            //同步到SAP创建预留单
            obligateVO = new ObligateVO();
            obligateVO.setMaterialNo(outDetailDO.getMaterialsNo());
            obligateVO.setAmount(outDetailDO.getDeliveryQty());
            obligateVO.setMoveType(threeGuaranteesOutDO.getSapTypeName());
            obligateVO.setWarehouseCode(threeGuaranteesOutDO.getOutLocation());
            obligateVO.setSapOutArea(threeGuaranteesOutDO.getSapOutArea());
            obligateVO.setInnerOrder(threeGuaranteesOutDO.getSapId());
            obligateVOList.add(obligateVO);
        }

//        //同步到SAP创建预留单，异步方式调用接口
//        ObligateHeaderVO headerVO = new ObligateHeaderVO();
//        headerVO.setBusinesId(threeGuaranteesOutDO.getId());
//        headerVO.setBusinesOrder(threeGuaranteesOutDO.getGuaranteesOutNo());
//        headerVO.setBusinesSingle(threeGuaranteesOutDO.getGuaranteesOutNo().substring(0, 4));
//        sapCommonService.createObligateOrder(headerVO, obligateVOList, null , orgId);
    }



    //塔机的请求涩会给你成出库单设置默认的参数
    private void defaultOutParamAssemble(ThreeGuaranteesPurDO purDO,ThreeGuaranteesOutVO outVo,String orgId,String outLocation){
        outVo.setOutArea(outLocation);
        outVo.setSapOutArea(outLocation);

        String customerId = purDO.getCustomerId();
        String customerName = purDO.getCustomerName();
        if(!StringUtils.isEmpty(customerId)){
            outVo.setPurchaseOrgId(customerId);
        }
        if(StringUtils.isEmpty(customerName)){
            outVo.setPurchaseOrgName(customerName);
        }
        outVo.setCreatePartId("455404133906644992");
        outVo.setCreatePartName("服务部");
        outVo.setCreateId("455404133906644992");
        outVo.setCreateName("接口用户");
        outVo.setOutLocation(outLocation);
    }


    @Transactional(rollbackFor = Exception.class)
    public ThreeGuaranteesOutDO addThreeOut4Tj(ThreeGuaranteesPurAddVO model,ThreeGuaranteesOutAddVO threeGuaranteesOutAddVO, String orgId, String userId)throws Exception{
        ThreeGuaranteesOutDO threeGuaranteesOutDO = new ThreeGuaranteesOutDO();
        BeanUtils.copyProperties(threeGuaranteesOutAddVO.getHeaderInfo(),threeGuaranteesOutDO);
        ActionResult<String> text = fastGenClient.textGuid();
        if (text.getCode() != ErrorCode.Success.getCode()) {
            throw new Exception("出库单生成主键异常");
        }
        threeGuaranteesOutDO.setId(text.getValue());
        threeGuaranteesOutDO.setGuaranteesOutNo(genDocumentService.getDocumentNo(BillDesc.ThreeOut));
        threeGuaranteesOutDO.setOrgId(orgId);
        threeGuaranteesOutDO.setCreateId(userId);
        threeGuaranteesOutDO.setCreateName(commonService.getUserName(userId));
        threeGuaranteesOutDO.setCreateDate(new Date());
        threeGuaranteesOutDO.setOutLocationStatus(0);
        List<FindMaterialsInfos> infos=new ArrayList<>();
        for (ThreeGuaranteesOutDetailVO detailVO : threeGuaranteesOutAddVO.getDetailList()) {
            FindMaterialsInfos findMaterialsInfos=new FindMaterialsInfos();
            findMaterialsInfos.setMaterialsNo(detailVO.getMaterialsNo());
            findMaterialsInfos.setAmount(detailVO.getDeliveryQty());
            infos.add(findMaterialsInfos);
        }
        FindMaterialsNumParam findMaterialsNumParam=new FindMaterialsNumParam();
        findMaterialsNumParam.setMaterialsNos(infos);
        findMaterialsNumParam.setOrgId(orgId);
        findMaterialsNumParam.setWarehousCode(threeGuaranteesOutAddVO.getHeaderInfo().getOutLocation());
        if(!warehouseInventoryService.findMaterialsNum(findMaterialsNumParam)){
            throw new Exception(ErrorCode.PartMaterialsNotNumber.getDesc());
        }
        boolean success;
        for(ThreeGuaranteesOutDetailVO detailVO:threeGuaranteesOutAddVO.getDetailList()){
            if(detailVO.getDeliveryQty() == null ){
                continue;
            }
            if (qtyIsOver(threeGuaranteesOutDO.getPurchaseNo(), detailVO)) {
                throw new Exception(ErrorCode.ThreeOutQtyError.getDesc());
            }
            ThreeGuaranteesOutDetailDO threeGuaranteesOutDetailDO = new ThreeGuaranteesOutDetailDO();
            BeanUtils.copyProperties(detailVO,threeGuaranteesOutDetailDO);
            ActionResult<String> textDetail=fastGenClient.textGuid();
            if(textDetail.getCode()!=ErrorCode.Success.getCode()){
                throw new Exception(ErrorCode.IllegalArument.getDesc());
            }
            threeGuaranteesOutDetailDO.setId(textDetail.getValue().toString());
            threeGuaranteesOutDetailDO.setGuaranteesOutNo(threeGuaranteesOutDO.getId());
            threeGuaranteesOutDetailDO.setRealOutQty(BigDecimal.ZERO);
            BigDecimal deliveryQty = detailVO.getDeliveryQty() == null ? BigDecimal.ZERO : detailVO.getDeliveryQty();
            BigDecimal outQty = detailVO.getOutQty() == null ? BigDecimal.ZERO : detailVO.getOutQty();
            threeGuaranteesOutDetailDO.setOutQty(deliveryQty.add(outQty));
            threeGuaranteesOutDetailDO.setOutLocationStatus(0);
            threeGuaranteesOutDetailDO.setPackNumber(BigDecimal.ZERO);
            success = threeGuaranteesOutDetailMapper.add(threeGuaranteesOutDetailDO)> 0;
            saveOutBarcode(threeGuaranteesOutDO.getGuaranteesOutNo(),threeGuaranteesOutDetailDO.getId(),detailVO,model);
            if(!success){
                throw new Exception("生成三包出库详情记录失败");
            }
            //更新其他三包出库单的已发货数量
            threeGuaranteesOutDetailMapper.updateOutQty(orgId, threeGuaranteesOutDetailDO.getOutQty(),
                    threeGuaranteesOutDO.getPurchaseNo(), detailVO.getMaterialsNo());

            //更新三包申请详情发货数量
            success = threeGuaranteesPurService.updateDetailQty(threeGuaranteesOutDO.getPurchaseNo(), threeGuaranteesOutDetailDO.getMaterialsNo(),
                    threeGuaranteesOutDetailDO.getOutQty(), orgId);
            if(!success){
                throw new Exception("更新三包申请详情发货数量失败");
            }
        }

        ThreeGuaranteesPurDO threeGuaranteesPurDO=threeGuaranteesPurService.itemByNo(threeGuaranteesOutDO.getPurchaseNo(),threeGuaranteesOutDO.getOrgId());
        if(threeGuaranteesPurDO==null){
            throw new Exception("三包申请单异常");
        }
        if (StringUtils.isBlank(threeGuaranteesPurDO.getCustomerId())) {
            // throw new Exception("三包申请单异常,客户信息不存在");
        }else{
            CompanyDealerDO companyDealerDO = companyDealerMapper.item(Long.parseLong(threeGuaranteesPurDO.getCustomerId()));
            if (companyDealerDO != null) {
                threeGuaranteesOutDO.setPurchaseOrgId(companyDealerDO.getDealerOrgId());
                threeGuaranteesOutDO.setPurchaseOrgName(companyDealerDO.getCompanyName());
            }
        }
        threeGuaranteesOutDO.setSettleTypeId(threeGuaranteesPurDO.getSettleTypeId());
        threeGuaranteesOutDO.setSettleTypeName(threeGuaranteesPurDO.getSettleTypeName());
        threeGuaranteesOutDO.setDeliveryTypeId(threeGuaranteesPurDO.getDeliveryTypeId());
        threeGuaranteesOutDO.setDeliveryTypeName(threeGuaranteesPurDO.getDeliveryTypeName());
        threeGuaranteesOutDO.setReceiverName(threeGuaranteesPurDO.getReceiverName());
        threeGuaranteesOutDO.setReceiverPhone(threeGuaranteesPurDO.getReceiverPhone());
        threeGuaranteesOutDO.setReceiverFax(threeGuaranteesPurDO.getReceiverFax());
        threeGuaranteesOutDO.setAddress(threeGuaranteesPurDO.getReceiverAddress());
        threeGuaranteesOutDO.setSendTypeChildId(threeGuaranteesPurDO.getSendTypeChildId());
        threeGuaranteesOutDO.setSendTypeChildName(threeGuaranteesPurDO.getSendTypeChildName());
        success = threeGuaranteesOutMapper.add(threeGuaranteesOutDO)>0;
        if(!success){
            throw new Exception("生成三包出库主记录失败");
        }

        //生成出库事物单
        threeGuaranteesOutAddVO.getHeaderInfo().setGuaranteesOutNo(threeGuaranteesOutDO.getGuaranteesOutNo());
        success = warehouseDeliveryService.saveByThreeGuaranteesOut(threeGuaranteesOutAddVO, userId, orgId);
        if(!success){
            throw new Exception("生成出库事物单失败");
        }

        //更新三包申请单可出库状态
        success = threeGuaranteesPurService.resetPurchaseStatus(threeGuaranteesOutDO.getPurchaseNo(),orgId);
        if(!success){
            throw new Exception("更新三包申请单可出库状态失败");
        }

        return threeGuaranteesOutDO;
    }

    public List<ThreeGuaranteesOutDO> findOutsByPurchaseNo(String purchaseNo){
        if(StringUtils.isEmpty(purchaseNo)){
            return Collections.EMPTY_LIST;
        }
        List<ThreeGuaranteesOutDO> guaranteesOuts = threeGuaranteesOutMapper.selectByPurchaseNo(purchaseNo);
        return guaranteesOuts;
    }

    public List<ThreeGuaranteesOutDO> listByCrmOrder(String crmOrder,String orgId){
        return threeGuaranteesOutMapper.listByCrmOrder(crmOrder,orgId);
    }

    /**
     * @Des 更新三包出库单中的返厂状态
     * @Date 2020/11/17 16:01
     * @Author wangzhaoyu
     * @Param [guaranteesOutNo, materialsNo, returnStatus]
     * @Return void
     */
    public void updateWornOutReturn(String guaranteesOutNo, String materialsNo, Integer returnStatus) {
        Date receiveDate = null;
        if(returnStatus != null && returnStatus.compareTo(WornoutReturnStatusEnum.RECEIVED.getStatus()) == 0){
            receiveDate = new Date();
        }
        threeGuaranteesOutDetailMapper.updateReturnStatus(guaranteesOutNo,materialsNo,returnStatus,receiveDate);
    }

    /**
     * @Des 更新三包出库单中的返程备注信息
     * @Date 2020/11/17 16:01
     * @Author wangzhaoyu
     * @Param [guaranteesOutNo, materialsNo, returnStatus]
     * @Return void
     */
    public void updateWornOutReturnRemark(String guaranteesOutNo, String materialsNo, String remark) {
        threeGuaranteesOutDetailMapper.updateWornreturnRemark(guaranteesOutNo,materialsNo,remark);
    }

    /**
    * @Desc   铲运同步服务单使用更换件，返回三包出库单
    * @Author Mr.dong
    * @Date   2020/12/16 9:19
    */
    @Transactional(rollbackFor = Exception.class)
    public ThreeGuaranteesOutDO synServiceTicket4Cy(ThreeGuaranteesPurAddVO model,String outLocation,String orgId) throws Exception {
        //生成三包申请单
        ActionResult<String> actionResult = doAddThreeGuaranteesPur4Cy(model);
        //生成三包出库单
        ThreeGuaranteesOutDO threeGuaranteesOutDO = threeGuaranteesOut4Cy(model,actionResult.getValue(), outLocation, orgId);
        //自动出库
        String applicationId = model.getHeaderInfo().getApplicationId();
        String applicationName = model.getHeaderInfo().getApplicationName();
        deliveryRecordAddAuto4Cy(threeGuaranteesOutDO,orgId,applicationId,applicationName);
        return threeGuaranteesOutDO;
    }

    private ActionResult doAddThreeGuaranteesPur4Cy(ThreeGuaranteesPurAddVO model) throws Exception {
        if (null == model || null == model.getHeaderInfo() || model.getDetailList().isEmpty()) {
            return new ActionResult(ErrorCode.IllegalArument.getCode(),ErrorCode.IllegalArument.getDesc());
        }

        externalParamCheckService.checkParam(fillNeedCheckParan(model));
        ActionResult result = threeGuaranteesPurService.addThreeGuaranteesPur4Cy(model);
        return result;
    }

    /**
     * 三包出库单生成（铲运）
     * @param outLocation
     * @param orgId
     */
    private ThreeGuaranteesOutDO threeGuaranteesOut4Cy(ThreeGuaranteesPurAddVO model,String purchaseNo,String outLocation,String orgId) throws Exception {
        //能匹配到出库仓库才进行出库单生成操作
        if(StringUtils.isEmpty(outLocation)){
            throw new Exception("出库仓库未空，无法生成出库单");
        }
        ThreeGuaranteesPurDO purDO = threeGuaranteesPurService.itemByPurNo(purchaseNo, orgId);
        ThreeGuaranteesOutVO outVO = new ThreeGuaranteesOutVO();
        List<ThreeGuaranteesOutDetailVO> detailList = new ArrayList<>();
        BeanUtils.copyProperties(purDO, outVO);
        //铲运出库单默认参数赋值
        defaultOutParamAssemble4Cy(purDO,outVO,orgId,outLocation);

        ThreeGuaranteesOutDetailVO outDetailVO;
        for (ThreeGuaranteesPurDetailDO purDetailDO : purDO.getPurDetailDOS()) {
            outDetailVO = new ThreeGuaranteesOutDetailVO();
            BeanUtils.copyProperties(purDetailDO, outDetailVO);
            //出库单的已发数量赋值为0；本次发货数量等于接口中的采购数量
            BigDecimal purchaseQty = purDetailDO.getPurchaseQty() == null ? BigDecimal.ZERO : purDetailDO.getPurchaseQty();
            outDetailVO.setDeliveryQty(purchaseQty);
            outDetailVO.setQty(purDetailDO.getPurchaseQty());
            detailList.add(outDetailVO);
        }
        ThreeGuaranteesOutAddVO threeGuaranteesOutAddVO = new ThreeGuaranteesOutAddVO();
        threeGuaranteesOutAddVO.setHeaderInfo(outVO);
        threeGuaranteesOutAddVO.setDetailList(detailList);
        ThreeGuaranteesOutDO threeGuaranteesOutDO = addThreeOut4Cy(model,threeGuaranteesOutAddVO, purDO.getOrgId(), purDO.getDispatcherId());
        // 创建预留单
        try{
            obligate4Cy(threeGuaranteesOutDO,orgId);
        }catch (Exception e){
            LogHelper.monitor("铲运三包出库单创建预留单异常"+e.getMessage());
        }
        return threeGuaranteesOutDO;
    }

    //设置铲运出库单默认参数
    private void defaultOutParamAssemble4Cy(ThreeGuaranteesPurDO purDO,ThreeGuaranteesOutVO outVo,String orgId,String outLocation){
        outVo.setOutArea(outLocation);
        outVo.setSapOutArea(outLocation);
        outVo.setOutLocation(outLocation);
        if(!StringUtils.isEmpty(purDO.getCustomerId())){
            outVo.setPurchaseOrgId(purDO.getCustomerId());
        }
        if(StringUtils.isEmpty(purDO.getCustomerName())){
            outVo.setPurchaseOrgName(purDO.getCustomerName());
        }
        outVo.setCreatePartId("455404133906644992");
        outVo.setCreatePartName("铲运服务部");
        outVo.setCreateId("455404133906644992");
        outVo.setCreateName("铲运接口用户");
    }

    /** 
    * @Desc   生成出库单（铲运）
    * @Author Mr.dong 
    * @Date   2020/12/16 11:26
    */ 
    @Transactional(rollbackFor = Exception.class)
    public ThreeGuaranteesOutDO addThreeOut4Cy(ThreeGuaranteesPurAddVO model,ThreeGuaranteesOutAddVO threeGuaranteesOutAddVO, String orgId, String userId) throws Exception{
        ThreeGuaranteesOutDO threeGuaranteesOutDO = new ThreeGuaranteesOutDO();
        ThreeGuaranteesOutVO outVO = threeGuaranteesOutAddVO.getHeaderInfo();
        List<ThreeGuaranteesOutDetailVO> detailList = threeGuaranteesOutAddVO.getDetailList();
        //查询三包申请单
        ThreeGuaranteesPurDO threeGuaranteesPurDO = threeGuaranteesPurService.itemByNo(outVO.getPurchaseNo(),orgId);
        if(threeGuaranteesPurDO == null){
            throw new Exception("三包申请单异常");
        }

        BeanUtils.copyProperties(outVO,threeGuaranteesOutDO);
        ActionResult<String> text = fastGenClient.textGuid();
        if (text.getCode() != ErrorCode.Success.getCode()) {
            throw new Exception("出库单生成主键异常");
        }
        threeGuaranteesOutDO.setId(text.getValue());
        threeGuaranteesOutDO.setGuaranteesOutNo(genDocumentService.getDocumentNo(BillDesc.ThreeOut));
        threeGuaranteesOutDO.setOrgId(orgId);
        threeGuaranteesOutDO.setCreateId(userId);
        threeGuaranteesOutDO.setCreateName(commonService.getUserName(userId));
        threeGuaranteesOutDO.setCreateDate(new Date());
        threeGuaranteesOutDO.setOutLocationStatus(0);
        //校验库存
        if(!checkCyWarehouseInventory(detailList,orgId,outVO.getOutLocation())){
            throw new Exception(ErrorCode.PartMaterialsNotNumber.getDesc());
        }
        boolean success;

        if (StringUtils.isNotBlank(threeGuaranteesPurDO.getCustomerId())) {
            CompanyDealerDO companyDealerDO = companyDealerMapper.item(Long.parseLong(threeGuaranteesPurDO.getCustomerId()));
            if (companyDealerDO != null) {
                threeGuaranteesOutDO.setPurchaseOrgId(companyDealerDO.getDealerOrgId());
                threeGuaranteesOutDO.setPurchaseOrgName(companyDealerDO.getCompanyName());
            }
        }
        threeGuaranteesOutDO.setSettleTypeId(threeGuaranteesPurDO.getSettleTypeId());
        threeGuaranteesOutDO.setSettleTypeName(threeGuaranteesPurDO.getSettleTypeName());
        threeGuaranteesOutDO.setDeliveryTypeId(threeGuaranteesPurDO.getDeliveryTypeId());
        threeGuaranteesOutDO.setDeliveryTypeName(threeGuaranteesPurDO.getDeliveryTypeName());
        threeGuaranteesOutDO.setReceiverName(threeGuaranteesPurDO.getReceiverName());
        threeGuaranteesOutDO.setReceiverPhone(threeGuaranteesPurDO.getReceiverPhone());
        threeGuaranteesOutDO.setReceiverFax(threeGuaranteesPurDO.getReceiverFax());
        threeGuaranteesOutDO.setAddress(threeGuaranteesPurDO.getReceiverAddress());
        threeGuaranteesOutDO.setSendTypeChildId(threeGuaranteesPurDO.getSendTypeChildId());
        threeGuaranteesOutDO.setSendTypeChildName(threeGuaranteesPurDO.getSendTypeChildName());
        success = threeGuaranteesOutMapper.add(threeGuaranteesOutDO)>0;
        if(!success){
            throw new Exception("生成三包出库主记录失败");
        }

        //生成出库事物单
        outVO.setGuaranteesOutNo(threeGuaranteesOutDO.getGuaranteesOutNo());
        success = warehouseDeliveryService.saveByThreeGuaranteesOut(threeGuaranteesOutAddVO, userId, orgId);
        if(!success){
            throw new Exception("生成出库事物单失败");
        }

        //更新三包申请单可出库状态
        success = threeGuaranteesPurService.resetPurchaseStatus(threeGuaranteesOutDO.getPurchaseNo(),orgId);
        if(!success){
            throw new Exception("更新三包申请单可出库状态失败");
        }

        for(ThreeGuaranteesOutDetailVO detailVO : detailList){
            if(detailVO.getDeliveryQty() == null ){
                continue;
            }
            if (qtyIsOver(threeGuaranteesOutDO.getPurchaseNo(), detailVO)) {
                throw new Exception(ErrorCode.ThreeOutQtyError.getDesc());
            }
            ThreeGuaranteesOutDetailDO threeGuaranteesOutDetailDO = new ThreeGuaranteesOutDetailDO();
            BeanUtils.copyProperties(detailVO,threeGuaranteesOutDetailDO);
            ActionResult<String> textDetail=fastGenClient.textGuid();
            if(textDetail.getCode()!=ErrorCode.Success.getCode()){
                throw new Exception(ErrorCode.IllegalArument.getDesc());
            }
            threeGuaranteesOutDetailDO.setId(textDetail.getValue().toString());
            threeGuaranteesOutDetailDO.setGuaranteesOutNo(threeGuaranteesOutDO.getId());
            threeGuaranteesOutDetailDO.setRealOutQty(BigDecimal.ZERO);
            BigDecimal deliveryQty = detailVO.getDeliveryQty() == null ? BigDecimal.ZERO : detailVO.getDeliveryQty();
            BigDecimal outQty = detailVO.getOutQty() == null ? BigDecimal.ZERO : detailVO.getOutQty();
            threeGuaranteesOutDetailDO.setOutQty(deliveryQty.add(outQty));
            threeGuaranteesOutDetailDO.setOutLocationStatus(0);
            threeGuaranteesOutDetailDO.setPackNumber(BigDecimal.ZERO);
            success = threeGuaranteesOutDetailMapper.add(threeGuaranteesOutDetailDO)> 0;
            if(!success){
                throw new Exception("生成三包出库详情记录失败");
            }
            //保存同一单据下出库条码
            saveOutBarcode(threeGuaranteesOutDO.getGuaranteesOutNo(),threeGuaranteesOutDetailDO.getId(),detailVO,model);

            //更新其他三包出库单的已发货数量
            threeGuaranteesOutDetailMapper.updateOutQty(orgId, threeGuaranteesOutDetailDO.getOutQty(),
                    threeGuaranteesOutDO.getPurchaseNo(), detailVO.getMaterialsNo());

            //更新三包申请详情发货数量
            success = threeGuaranteesPurService.updateDetailQty4Cy(threeGuaranteesPurDO.getId(), threeGuaranteesOutDetailDO.getMaterialsNo(),
                    threeGuaranteesOutDetailDO.getOutQty());
            if(!success){
                throw new Exception("更新三包申请详情发货数量失败");
            }
        }

        return threeGuaranteesOutDO;
    }

    /** 
    * @Desc   校验库存 
    * @Author Mr.dong 
    * @Date   2020/12/16 11:54
    */ 
    public boolean checkCyWarehouseInventory(List<ThreeGuaranteesOutDetailVO> detailList,String orgId,String outLocation){
        List<FindMaterialsInfos> infos = new ArrayList<>();
        FindMaterialsInfos findMaterialsInfos;
        for (ThreeGuaranteesOutDetailVO detailVO : detailList) {
            findMaterialsInfos = new FindMaterialsInfos();
            findMaterialsInfos.setMaterialsNo(detailVO.getMaterialsNo());
            findMaterialsInfos.setAmount(detailVO.getDeliveryQty());
            infos.add(findMaterialsInfos);
        }
        FindMaterialsNumParam findMaterialsNumParam=new FindMaterialsNumParam();
        findMaterialsNumParam.setMaterialsNos(infos);
        findMaterialsNumParam.setOrgId(orgId);
        findMaterialsNumParam.setWarehousCode(outLocation);
        return warehouseInventoryService.cyFindMaterialsNum(findMaterialsNumParam);

    }

    /** 
    * @Desc   三包出库创建预留单(铲运)
    * @Author Mr.dong 
    * @Date   2020/12/16 16:00
    */ 
    private void obligate4Cy(ThreeGuaranteesOutDO threeGuaranteesOutDO,String orgId) throws Exception {
        String outId = threeGuaranteesOutDO.getId();
        List<ThreeGuaranteesOutDetailDO> details = threeGuaranteesOutDetailMapper.list(outId);
        List<ObligateVO> obligateVOList = new ArrayList<>();
        ObligateVO obligateVO;
        for (ThreeGuaranteesOutDetailDO outDetailDO: details) {
            //同步到SAP创建预留单
            obligateVO = new ObligateVO();
            obligateVO.setMaterialNo(outDetailDO.getMaterialsNo());
            obligateVO.setAmount(outDetailDO.getDeliveryQty());
            obligateVO.setMoveType(threeGuaranteesOutDO.getSapTypeName());
            obligateVO.setWarehouseCode(threeGuaranteesOutDO.getOutLocation());
            obligateVO.setSapOutArea(threeGuaranteesOutDO.getSapOutArea());
            obligateVO.setInnerOrder(threeGuaranteesOutDO.getSapId());
            obligateVOList.add(obligateVO);
        }

//        //同步到SAP创建预留单，异步方式调用接口
//        ObligateHeaderVO headerVO = new ObligateHeaderVO();
//        headerVO.setBusinesId(threeGuaranteesOutDO.getId());
//        headerVO.setBusinesOrder(threeGuaranteesOutDO.getGuaranteesOutNo());
//        headerVO.setBusinesSingle(threeGuaranteesOutDO.getGuaranteesOutNo().substring(0, 4));
//        sapCommonService.createObligateOrder(headerVO, obligateVOList, null , orgId);
    }

    /** 
    * @Desc   服务更换件接口自动出库(铲运)
    * @Author Mr.dong 
    * @Date   2020/12/16 16:08
    */ 
    private void deliveryRecordAddAuto4Cy(ThreeGuaranteesOutDO threeGuaranteesOutDO,String orgId,String userId,String userName) throws Exception {
        LogHelper.monitor("铲运条码自动出库开始》》》》》》》》》》》》》》》》》》》》");
        log.info("铲运条码自动出库参数为threeGuaranteesOutDO:【{}】",JSON.toJSONString(threeGuaranteesOutDO));
        String guaranteesOutNo = threeGuaranteesOutDO.getGuaranteesOutNo();
        // 获取要自动出库的三包单中的条码详情
        List<ThreeGuaranteesOutBarcodeDO> outBarcodeDOS = threeGuaranteesOutBarcodeMapper.getByGuaranteesOutNo(guaranteesOutNo);
        log.info("铲运条码自动出库条码信息【{}】",outBarcodeDOS);
        // 遍历处理每个条码
        for(ThreeGuaranteesOutBarcodeDO outBarcodeDO : outBarcodeDOS){
            String outBarcode = outBarcodeDO.getBarcode();
            BarcodeManageDO barcodeDO = barcodeManageMapper.item(outBarcode, orgId);
            if(barcodeDO == null){
                log.error("铲运条码自动出库条码【】不存在",outBarcode);
                throw new Exception("条码"+outBarcode+"不存在");
            }
            if(barcodeDO.getBarcodeFlag() == 1 && "3".equals(barcodeDO.getBarcodeStatus())){
                log.info("铲运条码自动出库条码【{}】已拆分",outBarcode);
                throw new Exception("条码"+outBarcode+"已拆分");
            }
            // 根据条码查找库存详情
            List<WarehouseDeliveryRecordAddVO> barcodesInventory = findByBarCodeFromInventory4Cy(outBarcodeDO.getNum(),guaranteesOutNo, barcodeDO, orgId);
            log.info("铲运自动出库条码拆分结果为【{}】",JSON.toJSONString(barcodesInventory));
            if(CollectionUtils.isEmpty(barcodesInventory)){
                log.info("条码【{}】出库拆分失败，不出库",outBarcode);
                throw new Exception("条码"+outBarcode+"出库拆分失败");
            }
            // 根据条码拆分信息自动出库
            autoOut4Cy(barcodesInventory,guaranteesOutNo,barcodeDO,orgId,userId,userName);
        }
    }

    /**
    * @Desc   获取条码拆分信息
    * @Author Mr.dong
    * @Date   2020/12/16 16:13
    */
    private List<WarehouseDeliveryRecordAddVO> findByBarCodeFromInventory4Cy(BigDecimal outNum,String guaranteesOutNo,BarcodeManageDO barcodeDO,String orgId) throws Exception {
        List<WarehouseDeliveryRecordAddVO> result = new ArrayList<>();
        String barCode = barcodeDO.getBarcode();
        if(outNum == null){
            throw new Exception("出库数量异常");
        }
        WarehouseDeliveryDO deliveryDO = warehouseDeliveryMapper.findByBusinessOrder(guaranteesOutNo, orgId);
        if(deliveryDO == null){
            throw new Exception("未生成出库事务单");
        }

        List<String> barcdoeList = new ArrayList<>();
        if (barcodeDO.getBarcodeFlag() == 0) { //总条码时查询分条码列表
            barcdoeList.addAll(barcodeManageMapper.findBarcodeByTotalBarcode(barCode, orgId));
        } else {
            barcdoeList.add(barCode);
        }
        if (ListUtil.isNullOrEmpty(barcdoeList)) {
            LogHelper.monitor("铲运自动出库条码"+barCode+"无记录");
            throw new Exception("条码"+barCode+"无记录");
        }
        List<WarehouseInventoryDO> inventoryDOList = warehouseInventoryMapper.selectByBarCodeList(barcdoeList, orgId, null);
        if(CollectionUtils.isEmpty(inventoryDOList)){
            LogHelper.monitor("铲运自动出库条码"+barCode+"无库存记录");
            throw new Exception("条码"+barCode+"无库存记录");
        }

        String materialNo = inventoryDOList.get(0).getMaterialNo();
        WarehouseDeliveryDetailDO warehouseDeliveryDetailDO = warehouseDeliveryDetailMapper.itemByMaterialsNo(orgId, deliveryDO.getBusinessOrder(), materialNo);
        if (warehouseDeliveryDetailDO == null) {
            LogHelper.monitor("自动出库零件"+materialNo+"与单据零件不匹配");
            throw new Exception("条码零件"+materialNo+"与单据零件不匹配");
        }
        //出库事务表中还未出库的数量
        BigDecimal noOutAMount = warehouseDeliveryDetailDO.getAmount().subtract(warehouseDeliveryDetailDO.getRealAmount() == null ? BigDecimal.ZERO : warehouseDeliveryDetailDO.getRealAmount());
        if (noOutAMount.compareTo(BigDecimal.ZERO) == 0) {
            throw new Exception("零件已全部出库");
        }
        inventoryDOList = filterInventoryList4Cy(deliveryDO, inventoryDOList, orgId);
        if(CollectionUtils.isEmpty(inventoryDOList)){
            throw new Exception("条码"+barCode+"所属仓库与单据出库仓库不一致");
        }

        BigDecimal tempAmount1 = BigDecimal.ZERO;
        BigDecimal tempAmount2 = BigDecimal.ZERO;
        for (WarehouseInventoryDO inventoryDO : inventoryDOList) {
            BigDecimal amount = inventoryDO.getAmount();
            WarehouseDeliveryRecordAddVO recordAddVO = new WarehouseDeliveryRecordAddVO();
            recordAddVO.setAmount(amount);//条码当前数量
            tempAmount1 = tempAmount1.add(amount);
            if (outNum.compareTo(tempAmount1) < 0) {
                recordAddVO.setSplitAmount(outNum.subtract(tempAmount2));//设置拆分数量
            } else {
                recordAddVO.setSplitAmount(BigDecimal.ZERO);//设置拆分数量
            }
            recordAddVO.setBarCode(inventoryDO.getBarCode());//条码
            recordAddVO.setBusinessOrder(guaranteesOutNo);//单据号
            result.add(recordAddVO);
            tempAmount2 = tempAmount2.add(amount);

            if (recordAddVO.getSplitAmount().compareTo(BigDecimal.ZERO) > 0 || outNum.compareTo(tempAmount2) == 0) {
                break;
            }
        }
        //如果走到这里说明全部都不需要拆分，即需要出库的零件数量大于库存数量
        if(outNum.compareTo(tempAmount1) > 0){
            throw new Exception("条码零件数量不足");
        }
        return result;
    }


    private List<WarehouseInventoryDO> filterInventoryList4Cy(WarehouseDeliveryDO deliveryDO, List<WarehouseInventoryDO> inventoryDOList, String orgId) throws Exception {
        List<WarehouseInventoryDO> result = new ArrayList<>();
        String warehouseCode = deliveryDO.getWarehouseCode();
        WarehouseDO warehouseDO = warehouseDOMapper.itemByWarehouseCode(orgId, warehouseCode);
        if (warehouseDO == null) {
            LogHelper.monitor("铲运自动出库未找到仓库"+warehouseCode);
            throw new Exception("未找到仓库信息");
        }
        //过滤获取库存表中仓库与本次出库仓库能对上的库存记录
        for (WarehouseInventoryDO inventoryDO : inventoryDOList) {
            if (deliveryDO.getWarehouseCode().equals(inventoryDO.getWarehouseCode())) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(inventoryDO.getCreateDate());
                calendar.add(Calendar.DATE, -1);
                Date now = calendar.getTime();
                if (warehouseDO.getFirstInOut().equals(new Integer("1")) && warehouseInventoryMapper.earliestInventory(orgId, inventoryDO.getMaterialNo(),
                        inventoryDO.getWarehouseCode(), inventoryDO.getAreaCode(), now) > 0) {
                    throw new Exception("该零件存在更早的库存条码");
                }
                result.add(inventoryDO);
            }
        }
        return result;
    }

    /**
    * @Desc   自动出库(铲运)
    * @Author Mr.dong
    * @Date   2020/12/16 17:25
    */
    private void autoOut4Cy(List<WarehouseDeliveryRecordAddVO> barcodesInventory,String guaranteesOutNo,BarcodeManageDO barcodeDO,String orgId,String userId,String userName) throws Exception {

        WarehouseDeliveryDetailVO model = new WarehouseDeliveryDetailVO();
        model.setBusinessOrder(guaranteesOutNo);
        model.setMaterialNo(barcodeDO.getMaterialsNo());
        model.setOrgId(orgId);
        List<WarehouseDeliveryDetailDO> deliveryDetailList = warehouseDeliveryDetailMapper.list(model);
        if(ListUtil.isNullOrEmpty(deliveryDetailList)){
            throw new Exception("此零件不属于出库单中零件");
        }

        //判断数量并自动拆分条码
        List<BarcodeManageVO> barcodeManageVOS = splitBarcode(barcodesInventory, deliveryDetailList.get(0).getAmount(), userId, userName, orgId);
        //批量插入
        for(int i = 0; i < barcodesInventory.size(); i++){
            WarehouseDeliveryRecordAddVO recordAddVO = barcodesInventory.get(i);
            addThreeOutAutoRecord4Cy(recordAddVO, userId, orgId, true);
        }
    }

    /**
    * @Desc   三包单据自动出库记录（铲运）
    * @Author Mr.dong
    * @Date   2020/12/16 17:22
    */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode addThreeOutAutoRecord4Cy(WarehouseDeliveryRecordAddVO warehouseDeliveryRecordVO, String userId, String orgId, boolean isLast) throws Exception{
        ActionResult<String> textResult = fastGenClient.textGuid();
        if (textResult.getCode() != ErrorCode.Success.getCode()) {
            throw new Exception("自动出库生成主键异常");
        }

        //根据条码获取条码实体
        String barCode = warehouseDeliveryRecordVO.getBarCode();
        BarcodeManageDO barcode = barcodeManageMapper.item(barCode, orgId);
        if(barcode == null){
            throw new Exception("条码"+ barCode +"不存在");
        }
        if(barcode.getBarcodeFlag() == 0){
            throw new Exception(ErrorCode.WarehouseBarcodeNotFound.getDesc());
        }
        //判断条码是否已经扫描出库
        if("2".equals(barcode.getBarcodeStatus())){
            log.error("条码【{}】不能重复出库",barCode);
            throw new Exception(ErrorCode.WarehouseOutboundDuplicate.getDesc());
        }

        //先判断库存表里是否有零件，零件数量是否够
        WarehouseInventoryDO warehouseInventoryDO = warehouseInventoryService.findByBarCode(barCode, orgId);
        if(warehouseInventoryDO == null || warehouseInventoryDO.getIsOut() == 1 ){
            log.error("条码【{}】为查询到库存信息",barCode);
            throw new Exception(ErrorCode.WarehouseNotFound.getDesc());
        }else if(warehouseInventoryDO.getStatus() == 1){
            log.error("条码【{}】零件已冻结",barCode);
            throw new Exception(ErrorCode.WarehouseFrozen.getDesc());
        }else if(warehouseInventoryDO.getAmount().compareTo(warehouseDeliveryRecordVO.getAmount()) < 0){
            log.error("条码【{}】零件数量不足",barCode);
            throw new Exception(ErrorCode.WarehouseAmountNotEqual.getDesc());
        }

        //根据业务单号和零件编码查询出库详情记录
        String businessOrder = warehouseDeliveryRecordVO.getBusinessOrder();
        businessOrder = businessOrder==null?"":businessOrder;
        String buinessSingle = "";

        if(businessOrder.length()>4){
            buinessSingle = businessOrder.substring(0, 4);
        }

        String returnMaterialBusinessSingle = businessOrder.substring(0, 5);

        //查找出库事物主记录，判断是否冲销
        WarehouseDeliveryDO deliveryDO = warehouseDeliveryMapper.findByBusinessOrder(businessOrder, orgId);
        if(deliveryDO == null){
            throw new Exception("未找到相关联的出库事物单主记录");
        }
        if(deliveryDO.getReverseState() != null && (deliveryDO.getReverseState() == 1 || deliveryDO.getReverseState() == 2)){
            throw new Exception("业务单据已被冲销，不允许出库");
        }
        //判断单据是否已经是完成状态
        if( deliveryDO.getStatus() != null && deliveryDO.getStatus() == 4){
            throw new Exception("业务单据已作废！");
        }

        //判断单据是否已经是完成状态
        if(deliveryDO.getStatus() != null && (deliveryDO.getStatus() == 2 || deliveryDO.getStatus() == 3)){
            throw new Exception("业务单据已完成！");
        }
        //判断是否退货
        if(deliveryDO.getIsReturn() != null && deliveryDO.getIsReturn() == 1){
            throw new Exception("业务单据已被退货，不允许出库");
        }

        //判断零件是否属于调出仓库零件
        if(deliveryDO.getWarehouseCode() != null && !deliveryDO.getWarehouseCode().equals(warehouseInventoryDO.getWarehouseCode())){
            throw new Exception("此零件不属于调出仓库零件");
        }

        if (null != deliveryDO.getWarehouseCode()){
            CompanyInfoDO companyInfoDO = companyInfoMapper.item(orgId);
            Integer isBarcode = companyInfoDO.getIsBarcode();
            int countIsBarCode = warehouseDOMapper.countIsBarCode(orgId, deliveryDO.getWarehouseCode());
            if ((null == isBarcode || 0 == isBarcode) && countIsBarCode <= 0){//非条码化企业且仓库不允许条码化返回错误信息
                throw new Exception(ErrorCode.NonBarcodedOutboundNotAllowBarCodeEntry.getDesc());
            }
        }

        //判断零件是否属于调出仓库中库区零件
        if(deliveryDO.getOutArea() != null && !deliveryDO.getOutArea().equals(warehouseInventoryDO.getAreaCode())){
            throw new Exception("此零件不属于调出库区零件");
        }

        //判断零件是否属于出库单中零件
        WarehouseDeliveryDetailVO deliveryDetailVO = new WarehouseDeliveryDetailVO();
        deliveryDetailVO.setBusinessOrder(businessOrder);
        deliveryDetailVO.setMaterialNo(warehouseInventoryDO.getMaterialNo());
        deliveryDetailVO.setOrgId(orgId);
        List<WarehouseDeliveryDetailDO> list = warehouseDeliveryDetailMapper.list(deliveryDetailVO);
        if(ListUtil.isNullOrEmpty(list)){
            throw new Exception("此零件不属于出库单中零件");
        }
        if (list.get(0).getStatus() == 2) {
            throw new Exception("此零件状态已完成");
        }
        if (list.get(0).getStatus() == 3) {
            throw new Exception("此零件状态已结单");
        }
        if(StringUtil.isNullOrEmpty(warehouseDeliveryRecordVO.getDeliveryReceiptNo())){
            if(list.get(0).getAmount().compareTo(warehouseInventoryDO.getAmount()) < 0){
                throw new Exception("实际出库数量不能大于计划出库数量");
            }
        }

        WarehouseDeliveryRecordDO warehouseDeliveryRecordDO = new WarehouseDeliveryRecordDO();
        BeanUtils.copyProperties(warehouseInventoryDO, warehouseDeliveryRecordDO);

        warehouseDeliveryRecordDO.setBarCode(warehouseInventoryDO.getBarCode());
        warehouseDeliveryRecordDO.setBusinessOrder(businessOrder);
        warehouseDeliveryRecordDO.setBusinessSingle(buinessSingle);
        warehouseDeliveryRecordDO.setAmount(warehouseDeliveryRecordVO.getAmount());
        warehouseDeliveryRecordDO.setId(textResult.getValue());
        warehouseDeliveryRecordDO.setCreateDate(new Date());
        warehouseDeliveryRecordDO.setCreaterId(userId);
        warehouseDeliveryRecordDO.setOrgId(orgId);
        warehouseDeliveryRecordDO.setDeliveryOrder(deliveryDO.getDeliveryOrder());
        warehouseDeliveryRecordDO.setCreaterName(commonService.getUserName(userId));
        warehouseDeliveryRecordDO.setDeliveryReceiptNo(warehouseDeliveryRecordVO.getDeliveryReceiptNo());

        boolean isSuccess = warehouseDeliveryRecordMapper.insert(warehouseDeliveryRecordDO)>0;
        if(!isSuccess){
            log.error("出库记录单warehouseDeliveryRecord插入数据失败，插入数据为【{}】",warehouseDeliveryRecordDO);
            throw new Exception("出库记录单操作失败");
        }

        //出库成功，库存表里相关记录更新

        if(isLast){
            //如果是发运交接单出库，有可能是一个条码分多次出库，在最后一次出库时更新条码已出库状态
            ErrorCode barcodeErrorCode = barcodeService.deliveryUpdateBarcode(businessOrder,warehouseDeliveryRecordDO.getBarCode(), BarcodeStatus.Status.OutStorage, orgId, userId,warehouseDeliveryRecordDO.getCreateDate());
            if(barcodeErrorCode.getCode() != 0){
                throw new Exception("生成出库记录时，更新条码状态失败");
            }
            isSuccess = warehouseInventoryService.saveByOutbound(warehouseInventoryDO, warehouseDeliveryRecordDO, userId);
            if(!isSuccess){
                throw new Exception("生成出库记录时，更新库存状态失败");
            }
        }
        Map<String, BigDecimal> map = warehouseDeliveryDetailService.updateByOutbound(warehouseDeliveryRecordDO.getDeliveryOrder(),
                warehouseDeliveryRecordDO.getMaterialNo(), warehouseDeliveryRecordVO.getAmount(), orgId);
        isSuccess = map.get("success").intValue()==1;
        if(!isSuccess){
            throw new Exception("生成出库记录时，更新出库事物单状态失败");
        }

        LogHelper.monitor("buinessSingle------------->"+buinessSingle);
        LogHelper.monitor("returnMaterialBusinessSingle----------------->"+returnMaterialBusinessSingle);

        //更新出库业务单据状态
        BigDecimal realAmount = map.get("realAmount");
        Integer singleState = map.get("singleState").intValue();
        Integer totalState = map.get("totalState").intValue();
        boolean updateReceipt = StringUtil.isNullOrEmpty(warehouseDeliveryRecordVO.getDeliveryReceiptNo());
        //更新三包出库单
        isSuccess = threeGuaranteesOutService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, updateReceipt);
        if(!isSuccess){
            throw new Exception("生成出库记录时，更新三包出库单和详情状态失败");
        }
        return ErrorCode.Success;

    }

    /**
     * 基础自动生成出库单
     */
    public ThreeGuaranteesOutDO jcAutoAddThreeGuaranteesOut(String purchaseNo,CompanyInfoDO companyInfo) throws Exception {
        String orgId = companyInfo.getOrgId();
        ThreeGuaranteesPurDO purDO = threeGuaranteesPurService.itemByPurNo(purchaseNo, orgId);
        List<ThreeGuaranteesOutDetailVO> detailList = new ArrayList<>();
        ThreeGuaranteesOutDetailVO outDetailVO;
        for (ThreeGuaranteesPurDetailDO purDetailDO : purDO.getPurDetailDOS()) {
            outDetailVO = new ThreeGuaranteesOutDetailVO();
            BeanUtils.copyProperties(purDetailDO, outDetailVO);
            //出库单的已发数量和本次发货数量等于接口中的采购数量
            BigDecimal purchaseQty = purDetailDO.getPurchaseQty() == null ? BigDecimal.ZERO : purDetailDO.getPurchaseQty();
            outDetailVO.setDeliveryQty(purchaseQty);
            outDetailVO.setQty(purDetailDO.getPurchaseQty());
            detailList.add(outDetailVO);
        }
        ThreeGuaranteesOutDO threeGuaranteesOutDO = new ThreeGuaranteesOutDO();
        BeanUtils.copyProperties(purDO,threeGuaranteesOutDO);
        ActionResult<String> text = fastGenClient.textGuid();
        if (text.getCode() != ErrorCode.Success.getCode()) {
            throw new Exception("出库单生成主键异常");
        }
        threeGuaranteesOutDO.setCreateId(null);
        threeGuaranteesOutDO.setCreateName(null);
        threeGuaranteesOutDO.setGuaranteesTypeName("三包出库");//默认写死
        threeGuaranteesOutDO.setId(text.getValue());
        threeGuaranteesOutDO.setGuaranteesOutNo(genDocumentService.getDocumentNo(BillDesc.ThreeOut));
        threeGuaranteesOutDO.setOrgId(orgId);
        threeGuaranteesOutDO.setCreateDate(new Date());
        threeGuaranteesOutDO.setOutLocationStatus(2);

        for(ThreeGuaranteesPurDetailDO purDetailDO : purDO.getPurDetailDOS()){
            BigDecimal purchaseQty = purDetailDO.getPurchaseQty();
            if(purchaseQty == null ){
                continue;
            }
            ThreeGuaranteesOutDetailDO threeGuaranteesOutDetailDO = new ThreeGuaranteesOutDetailDO();
            BeanUtils.copyProperties(purDetailDO, threeGuaranteesOutDetailDO);
            ActionResult<String> textDetail=fastGenClient.textGuid();
            if(textDetail.getCode()!=ErrorCode.Success.getCode()){
                throw new Exception(ErrorCode.IllegalArument.getDesc());
            }
            threeGuaranteesOutDetailDO.setId(textDetail.getValue());
            threeGuaranteesOutDetailDO.setGuaranteesOutNo(threeGuaranteesOutDO.getId());
            threeGuaranteesOutDetailDO.setQty(purchaseQty);
            threeGuaranteesOutDetailDO.setRealOutQty(purchaseQty);
            threeGuaranteesOutDetailDO.setOutQty(purchaseQty);
            threeGuaranteesOutDetailDO.setDeliveryQty(purchaseQty);
            threeGuaranteesOutDetailDO.setOutLocationStatus(2);//默认已出库
            threeGuaranteesOutDetailDO.setPackNumber(BigDecimal.ZERO);
            boolean success = threeGuaranteesOutDetailMapper.add(threeGuaranteesOutDetailDO)> 0;
            if(!success){
                throw new Exception("生成三包出库详情记录失败");
            }
        }

        ThreeGuaranteesPurDO threeGuaranteesPurDO=threeGuaranteesPurService.itemByNo(threeGuaranteesOutDO.getPurchaseNo(),threeGuaranteesOutDO.getOrgId());
        if (StringUtils.isBlank(threeGuaranteesPurDO.getCustomerId())) {
            // throw new Exception("三包申请单异常,客户信息不存在");
        }else{
            CompanyDealerDO companyDealerDO = companyDealerMapper.item(Long.parseLong(threeGuaranteesPurDO.getCustomerId()));
            if (companyDealerDO != null) {
                threeGuaranteesOutDO.setPurchaseOrgId(companyDealerDO.getDealerOrgId());
                threeGuaranteesOutDO.setPurchaseOrgName(companyDealerDO.getCompanyName());
            }
        }
        threeGuaranteesOutDO.setSettleTypeId(threeGuaranteesPurDO.getSettleTypeId());
        threeGuaranteesOutDO.setSettleTypeName(threeGuaranteesPurDO.getSettleTypeName());
        threeGuaranteesOutDO.setDeliveryTypeId(threeGuaranteesPurDO.getDeliveryTypeId());
        threeGuaranteesOutDO.setDeliveryTypeName(threeGuaranteesPurDO.getDeliveryTypeName());
        threeGuaranteesOutDO.setReceiverName(threeGuaranteesPurDO.getReceiverName());
        threeGuaranteesOutDO.setReceiverPhone(threeGuaranteesPurDO.getReceiverPhone());
        threeGuaranteesOutDO.setReceiverFax(threeGuaranteesPurDO.getReceiverFax());
        threeGuaranteesOutDO.setAddress(threeGuaranteesPurDO.getReceiverAddress());
        threeGuaranteesOutDO.setSendTypeChildId(threeGuaranteesPurDO.getSendTypeChildId());
        threeGuaranteesOutDO.setSendTypeChildName(threeGuaranteesPurDO.getSendTypeChildName());
        threeGuaranteesOutDO.setNote(threeGuaranteesPurDO.getNote());
        boolean success = threeGuaranteesOutMapper.add(threeGuaranteesOutDO) > 0;
        if (!success) {
            throw new Exception("生成三包出库主记录失败");
        }
        return threeGuaranteesOutDO;
    }

//    /**
//     * 随车自动生成出库单
//     */
//    ThreeGuaranteesOutDO scAutoThreeGuaranteesOut(ThreeGuaranteesPurAddVO model,String purchaseNo,CompanyInfoDO companyInfo) throws Exception {
//        String orgId = companyInfo.getOrgId();
//        ThreeGuaranteesPurDO purDO = threeGuaranteesPurService.itemByPurNo(purchaseNo, orgId);
//        ThreeGuaranteesOutVO outVO = new ThreeGuaranteesOutVO();
//        List<ThreeGuaranteesOutDetailVO> detailList = new ArrayList<>();
//        BeanUtils.copyProperties(purDO, outVO);
//        ThreeGuaranteesOutDetailVO outDetailVO;
//        for (ThreeGuaranteesPurDetailDO purDetailDO : purDO.getPurDetailDOS()) {
//            outDetailVO = new ThreeGuaranteesOutDetailVO();
//            BeanUtils.copyProperties(purDetailDO, outDetailVO);
//            //出库单的已发数量赋值为0和本次发货数量等于接口中的采购数量
//            BigDecimal purchaseQty = purDetailDO.getPurchaseQty() == null ? BigDecimal.ZERO : purDetailDO.getPurchaseQty();
//            outDetailVO.setDeliveryQty(purchaseQty);
//            outDetailVO.setQty(purDetailDO.getPurchaseQty());
//            detailList.add(outDetailVO);
//        }
//        ThreeGuaranteesOutAddVO threeGuaranteesOutAddVO = new ThreeGuaranteesOutAddVO();
//        threeGuaranteesOutAddVO.setHeaderInfo(outVO);
//        threeGuaranteesOutAddVO.setDetailList(detailList);
//        ThreeGuaranteesOutDO threeGuaranteesOutDO = autoAddThreeOut4Sc(threeGuaranteesOutAddVO, purDO.getOrgId());
//        // 创建预留单
//        try{
//            obligate4Tj(threeGuaranteesOutDO,orgId);
//        }catch (Exception e){
//            LogHelper.monitor("随车三包出库单创建预留单异常"+e.getMessage());
//        }
//        return threeGuaranteesOutDO;
//    }
//

    //    @Transactional(rollbackFor = Exception.class)
//    public ThreeGuaranteesOutDO autoAddThreeOut4Sc(ThreeGuaranteesOutAddVO threeGuaranteesOutAddVO, String orgId)throws Exception{
//        ThreeGuaranteesOutDO threeGuaranteesOutDO = new ThreeGuaranteesOutDO();
//        BeanUtils.copyProperties(threeGuaranteesOutAddVO.getHeaderInfo(),threeGuaranteesOutDO);
//        ActionResult<String> text = fastGenClient.textGuid();
//        if (text.getCode() != ErrorCode.Success.getCode()) {
//            throw new Exception("出库单生成主键异常");
//        }
//        threeGuaranteesOutDO.setOutLocation(scThreeOutDefaultLocation);
//        threeGuaranteesOutDO.setOutArea(scThreeOutDefaultArea);
//        threeGuaranteesOutDO.setSapOutArea(scThreeOutDefaultArea);
//        threeGuaranteesOutDO.setCreateId(scThreeOutDefaultCreateId);
//        threeGuaranteesOutDO.setCreateName(scThreeOutDefaultCreateName);
//        threeGuaranteesOutDO.setCreatePartId(scThreeOutDefaultCreatePartId);
//        threeGuaranteesOutDO.setCreatePartName(scThreeOutDefaultCreatePartName);
//        threeGuaranteesOutDO.setGuaranteesTypeName("三包出库");//默认写死
//        threeGuaranteesOutDO.setId(text.getValue());
//        threeGuaranteesOutDO.setGuaranteesOutNo(genDocumentService.getDocumentNo(BillDesc.ThreeOut));
//        threeGuaranteesOutDO.setOrgId(orgId);
//        threeGuaranteesOutDO.setCreateDate(new Date());
//        threeGuaranteesOutDO.setOutLocationStatus(0);
//        boolean success;
//        List<ThreeGuaranteesOutDetailDO> details = new ArrayList<>();
//        for(ThreeGuaranteesOutDetailVO detailVO:threeGuaranteesOutAddVO.getDetailList()){
//            if(detailVO.getDeliveryQty() == null ){
//                continue;
//            }
//            if (qtyIsOver(threeGuaranteesOutDO.getPurchaseNo(), detailVO)) {
//                throw new Exception(ErrorCode.ThreeOutQtyError.getDesc());
//            }
//            ThreeGuaranteesOutDetailDO threeGuaranteesOutDetailDO = new ThreeGuaranteesOutDetailDO();
//            BeanUtils.copyProperties(detailVO,threeGuaranteesOutDetailDO);
//            ActionResult<String> textDetail=fastGenClient.textGuid();
//            if(textDetail.getCode()!=ErrorCode.Success.getCode()){
//                throw new Exception(ErrorCode.IllegalArument.getDesc());
//            }
//            threeGuaranteesOutDetailDO.setId(textDetail.getValue());
//            threeGuaranteesOutDetailDO.setGuaranteesOutNo(threeGuaranteesOutDO.getId());
//            threeGuaranteesOutDetailDO.setRealOutQty(BigDecimal.ZERO);
//            BigDecimal deliveryQty = detailVO.getDeliveryQty() == null ? BigDecimal.ZERO : detailVO.getDeliveryQty();
//            BigDecimal outQty = detailVO.getOutQty() == null ? BigDecimal.ZERO : detailVO.getOutQty();
//            threeGuaranteesOutDetailDO.setOutQty(deliveryQty.add(outQty));
//            threeGuaranteesOutDetailDO.setOutLocationStatus(0);
//            threeGuaranteesOutDetailDO.setPackNumber(BigDecimal.ZERO);
//            success = threeGuaranteesOutDetailMapper.add(threeGuaranteesOutDetailDO)> 0;
//            if(!success){
//                throw new Exception("生成三包出库详情记录失败");
//            }
//            details.add(threeGuaranteesOutDetailDO);
//            //更新其他三包出库单的已发货数量
//            threeGuaranteesOutDetailMapper.updateOutQty(orgId, threeGuaranteesOutDetailDO.getOutQty(),
//                    threeGuaranteesOutDO.getPurchaseNo(), detailVO.getMaterialsNo());
//
//            //更新三包申请详情发货数量
//            success = threeGuaranteesPurService.updateDetailQty(threeGuaranteesOutDO.getPurchaseNo(), threeGuaranteesOutDetailDO.getMaterialsNo(),
//                    threeGuaranteesOutDetailDO.getOutQty(), orgId);
//            if(!success){
//                throw new Exception("更新三包申请详情发货数量失败");
//            }
//        }
//
//        ThreeGuaranteesPurDO threeGuaranteesPurDO=threeGuaranteesPurService.itemByNo(threeGuaranteesOutDO.getPurchaseNo(),threeGuaranteesOutDO.getOrgId());
//        if(threeGuaranteesPurDO==null){
//            throw new Exception("三包申请单异常");
//        }
//        if (StringUtils.isBlank(threeGuaranteesPurDO.getCustomerId())) {
//            // throw new Exception("三包申请单异常,客户信息不存在");
//        }else{
//            CompanyDealerDO companyDealerDO = companyDealerMapper.item(Long.parseLong(threeGuaranteesPurDO.getCustomerId()));
//            if (companyDealerDO != null) {
//                threeGuaranteesOutDO.setPurchaseOrgId(companyDealerDO.getDealerOrgId());
//                threeGuaranteesOutDO.setPurchaseOrgName(companyDealerDO.getCompanyName());
//            }
//        }
//        threeGuaranteesOutDO.setSettleTypeId(threeGuaranteesPurDO.getSettleTypeId());
//        threeGuaranteesOutDO.setSettleTypeName(threeGuaranteesPurDO.getSettleTypeName());
//        threeGuaranteesOutDO.setDeliveryTypeId(threeGuaranteesPurDO.getDeliveryTypeId());
//        threeGuaranteesOutDO.setDeliveryTypeName(threeGuaranteesPurDO.getDeliveryTypeName());
//        threeGuaranteesOutDO.setReceiverName(threeGuaranteesPurDO.getReceiverName());
//        threeGuaranteesOutDO.setReceiverPhone(threeGuaranteesPurDO.getReceiverPhone());
//        threeGuaranteesOutDO.setReceiverFax(threeGuaranteesPurDO.getReceiverFax());
//        threeGuaranteesOutDO.setAddress(threeGuaranteesPurDO.getReceiverAddress());
//        threeGuaranteesOutDO.setSendTypeChildId(threeGuaranteesPurDO.getSendTypeChildId());
//        threeGuaranteesOutDO.setSendTypeChildName(threeGuaranteesPurDO.getSendTypeChildName());
//        threeGuaranteesOutDO.setNote(threeGuaranteesPurDO.getNote());
//        success = threeGuaranteesOutMapper.add(threeGuaranteesOutDO)>0;
//        if(!success){
//            throw new Exception("生成三包出库主记录失败");
//        }
//
//        //生成出库事物单
//        threeGuaranteesOutAddVO.getHeaderInfo().setGuaranteesOutNo(threeGuaranteesOutDO.getGuaranteesOutNo());
//        success = warehouseDeliveryService.saveScThreeOutWarehouseDelivery(threeGuaranteesOutDO,details, orgId);
//        if(!success){
//            throw new Exception("生成出库事物单失败");
//        }
//
//        //更新三包申请单可出库状态
//        success = threeGuaranteesPurService.resetPurchaseStatus(threeGuaranteesOutDO.getPurchaseNo(),orgId);
//        if(!success){
//            throw new Exception("更新三包申请单可出库状态失败");
//        }
//
//        return threeGuaranteesOutDO;
//    }
//
    public ErrorCode revert(String id) throws Exception {
        ThreeGuaranteesPurDO threeGuaranteesPurDO = threeGuaranteesPurMapper.item(id);
        if (threeGuaranteesPurDO == null) {
            throw new Exception("三包申请单不存在");
        }
        if (!"2".equals(threeGuaranteesPurDO.getGuaraenteesStatus()) && !"1".equals(threeGuaranteesPurDO.getGuaraenteesStatus())) {
            throw new Exception("此状态不允许此操作");
        }
        List<String> outBillNos = threeGuaranteesOutService.getOutBillNos(threeGuaranteesPurDO.getPurchaseNo());
        if (CollectionUtils.isNotEmpty(outBillNos)) {
            throw new Exception("已存在相关的出库单据");
        }
        int resultCount = threeGuaranteesPurMapper.revert(id);
        if(resultCount == 0) {
            throw new Exception("请刷新后检查单据状态（审核通过且未出库）");
        }
        return ErrorCode.Success;
    }
    
    public List<String> getOutBillNos(String purchaseNo) {
        return threeGuaranteesOutMapper.getOutBillNos(purchaseNo);
    }

}
